aboutsummaryrefslogtreecommitdiffstats
path: root/lib/IR/DebugLoc.cpp
blob: 718da852fec34ae94ffa29c73808597dfe867f64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
//===-- DebugLoc.cpp - Implement DebugLoc class ---------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/IR/DebugLoc.h"
#include "LLVMContextImpl.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/IR/DebugInfo.h"
using namespace llvm;

//===----------------------------------------------------------------------===//
// DebugLoc Implementation
//===----------------------------------------------------------------------===//

MDNode *DebugLoc::getScope(const LLVMContext &Ctx) const {
  if (ScopeIdx == 0) return nullptr;
  
  if (ScopeIdx > 0) {
    // Positive ScopeIdx is an index into ScopeRecords, which has no inlined-at
    // position specified.
    assert(unsigned(ScopeIdx) <= Ctx.pImpl->ScopeRecords.size() &&
           "Invalid ScopeIdx!");
    return Ctx.pImpl->ScopeRecords[ScopeIdx-1].get();
  }
  
  // Otherwise, the index is in the ScopeInlinedAtRecords array.
  assert(unsigned(-ScopeIdx) <= Ctx.pImpl->ScopeInlinedAtRecords.size() &&
         "Invalid ScopeIdx");
  return Ctx.pImpl->ScopeInlinedAtRecords[-ScopeIdx-1].first.get();
}

MDNode *DebugLoc::getInlinedAt(const LLVMContext &Ctx) const {
  // Positive ScopeIdx is an index into ScopeRecords, which has no inlined-at
  // position specified.  Zero is invalid.
  if (ScopeIdx >= 0) return nullptr;
  
  // Otherwise, the index is in the ScopeInlinedAtRecords array.
  assert(unsigned(-ScopeIdx) <= Ctx.pImpl->ScopeInlinedAtRecords.size() &&
         "Invalid ScopeIdx");
  return Ctx.pImpl->ScopeInlinedAtRecords[-ScopeIdx-1].second.get();
}

/// Return both the Scope and the InlinedAt values.
void DebugLoc::getScopeAndInlinedAt(MDNode *&Scope, MDNode *&IA,
                                    const LLVMContext &Ctx) const {
  if (ScopeIdx == 0) {
    Scope = IA = nullptr;
    return;
  }
  
  if (ScopeIdx > 0) {
    // Positive ScopeIdx is an index into ScopeRecords, which has no inlined-at
    // position specified.
    assert(unsigned(ScopeIdx) <= Ctx.pImpl->ScopeRecords.size() &&
           "Invalid ScopeIdx!");
    Scope = Ctx.pImpl->ScopeRecords[ScopeIdx-1].get();
    IA = nullptr;
    return;
  }
  
  // Otherwise, the index is in the ScopeInlinedAtRecords array.
  assert(unsigned(-ScopeIdx) <= Ctx.pImpl->ScopeInlinedAtRecords.size() &&
         "Invalid ScopeIdx");
  Scope = Ctx.pImpl->ScopeInlinedAtRecords[-ScopeIdx-1].first.get();
  IA    = Ctx.pImpl->ScopeInlinedAtRecords[-ScopeIdx-1].second.get();
}

MDNode *DebugLoc::getScopeNode(const LLVMContext &Ctx) const {
  if (MDNode *InlinedAt = getInlinedAt(Ctx))
    return DebugLoc::getFromDILocation(InlinedAt).getScopeNode(Ctx);
  return getScope(Ctx);
}

DebugLoc DebugLoc::getFnDebugLoc(const LLVMContext &Ctx) const {
  const MDNode *Scope = getScopeNode(Ctx);
  DISubprogram SP = getDISubprogram(Scope);
  if (SP.isSubprogram())
    return DebugLoc::get(SP.getScopeLineNumber(), 0, SP);

  return DebugLoc();
}

DebugLoc DebugLoc::get(unsigned Line, unsigned Col,
                       MDNode *Scope, MDNode *InlinedAt) {
  DebugLoc Result;
  
  // If no scope is available, this is an unknown location.
  if (!Scope) return Result;

  // Saturate line and col to "unknown".
  if (Col > 255) Col = 0;
  if (Line >= (1 << 24)) Line = 0;
  Result.LineCol = Line | (Col << 24);
  
  LLVMContext &Ctx = Scope->getContext();
  
  // If there is no inlined-at location, use the ScopeRecords array.
  if (!InlinedAt)
    Result.ScopeIdx = Ctx.pImpl->getOrAddScopeRecordIdxEntry(Scope, 0);
  else
    Result.ScopeIdx = Ctx.pImpl->getOrAddScopeInlinedAtIdxEntry(Scope,
                                                                InlinedAt, 0);

  return Result;
}

/// getAsMDNode - This method converts the compressed DebugLoc node into a
/// DILocation-compatible MDNode.
MDNode *DebugLoc::getAsMDNode(const LLVMContext &Ctx) const {
  if (isUnknown()) return nullptr;
  
  MDNode *Scope, *IA;
  getScopeAndInlinedAt(Scope, IA, Ctx);
  assert(Scope && "If scope is null, this should be isUnknown()");
  
  LLVMContext &Ctx2 = Scope->getContext();
  Type *Int32 = Type::getInt32Ty(Ctx2);
  Value *Elts[] = {
    ConstantInt::get(Int32, getLine()), ConstantInt::get(Int32, getCol()),
    Scope, IA
  };
  return MDNode::get(Ctx2, Elts);
}

/// getFromDILocation - Translate the DILocation quad into a DebugLoc.
DebugLoc DebugLoc::getFromDILocation(MDNode *N) {
  DILocation Loc(N);
  MDNode *Scope = Loc.getScope();
  if (!Scope) return DebugLoc();
  return get(Loc.getLineNumber(), Loc.getColumnNumber(), Scope,
             Loc.getOrigLocation());
}

/// getFromDILexicalBlock - Translate the DILexicalBlock into a DebugLoc.
DebugLoc DebugLoc::getFromDILexicalBlock(MDNode *N) {
  DILexicalBlock LexBlock(N);
  MDNode *Scope = LexBlock.getContext();
  if (!Scope) return DebugLoc();
  return get(LexBlock.getLineNumber(), LexBlock.getColumnNumber(), Scope,
             nullptr);
}

void DebugLoc::dump(const LLVMContext &Ctx) const {
#ifndef NDEBUG
  if (!isUnknown()) {
    dbgs() << getLine();
    if (getCol() != 0)
      dbgs() << ',' << getCol();
    DebugLoc InlinedAtDL = DebugLoc::getFromDILocation(getInlinedAt(Ctx));
    if (!InlinedAtDL.isUnknown()) {
      dbgs() << " @ ";
      InlinedAtDL.dump(Ctx);
    } else
      dbgs() << "\n";
  }
#endif
}

void DebugLoc::print(const LLVMContext &Ctx, raw_ostream &OS) const {
  if (!isUnknown()) {
    // Print source line info.
    DIScope Scope(getScope(Ctx));
    assert((!Scope || Scope.isScope()) &&
           "Scope of a DebugLoc should be null or a DIScope.");
    if (Scope)
      OS << Scope.getFilename();
    else
      OS << "<unknown>";
    OS << ':' << getLine();
    if (getCol() != 0)
      OS << ':' << getCol();
    DebugLoc InlinedAtDL = DebugLoc::getFromDILocation(getInlinedAt(Ctx));
    if (!InlinedAtDL.isUnknown()) {
      OS << " @[ ";
      InlinedAtDL.print(Ctx, OS);
      OS << " ]";
    }
  }
}

//===----------------------------------------------------------------------===//
// DenseMap specialization
//===----------------------------------------------------------------------===//

unsigned DenseMapInfo<DebugLoc>::getHashValue(const DebugLoc &Key) {
  return static_cast<unsigned>(hash_combine(Key.LineCol, Key.ScopeIdx));
}

//===----------------------------------------------------------------------===//
// LLVMContextImpl Implementation
//===----------------------------------------------------------------------===//

int LLVMContextImpl::getOrAddScopeRecordIdxEntry(MDNode *Scope,
                                                 int ExistingIdx) {
  // If we already have an entry for this scope, return it.
  int &Idx = ScopeRecordIdx[Scope];
  if (Idx) return Idx;
  
  // If we don't have an entry, but ExistingIdx is specified, use it.
  if (ExistingIdx)
    return Idx = ExistingIdx;
  
  // Otherwise add a new entry.
  
  // Start out ScopeRecords with a minimal reasonable size to avoid
  // excessive reallocation starting out.
  if (ScopeRecords.empty())
    ScopeRecords.reserve(128);
  
  // Index is biased by 1 for index.
  Idx = ScopeRecords.size()+1;
  ScopeRecords.push_back(DebugRecVH(Scope, this, Idx));
  return Idx;
}

int LLVMContextImpl::getOrAddScopeInlinedAtIdxEntry(MDNode *Scope, MDNode *IA,
                                                    int ExistingIdx) {
  // If we already have an entry, return it.
  int &Idx = ScopeInlinedAtIdx[std::make_pair(Scope, IA)];
  if (Idx) return Idx;
  
  // If we don't have an entry, but ExistingIdx is specified, use it.
  if (ExistingIdx)
    return Idx = ExistingIdx;
  
  // Start out ScopeInlinedAtRecords with a minimal reasonable size to avoid
  // excessive reallocation starting out.
  if (ScopeInlinedAtRecords.empty())
    ScopeInlinedAtRecords.reserve(128);
    
  // Index is biased by 1 and negated.
  Idx = -ScopeInlinedAtRecords.size()-1;
  ScopeInlinedAtRecords.push_back(std::make_pair(DebugRecVH(Scope, this, Idx),
                                                 DebugRecVH(IA, this, Idx)));
  return Idx;
}


//===----------------------------------------------------------------------===//
// DebugRecVH Implementation
//===----------------------------------------------------------------------===//

/// deleted - The MDNode this is pointing to got deleted, so this pointer needs
/// to drop to null and we need remove our entry from the DenseMap.
void DebugRecVH::deleted() {
  // If this is a non-canonical reference, just drop the value to null, we know
  // it doesn't have a map entry.
  if (Idx == 0) {
    setValPtr(nullptr);
    return;
  }
    
  MDNode *Cur = get();
  
  // If the index is positive, it is an entry in ScopeRecords.
  if (Idx > 0) {
    assert(Ctx->ScopeRecordIdx[Cur] == Idx && "Mapping out of date!");
    Ctx->ScopeRecordIdx.erase(Cur);
    // Reset this VH to null and we're done.
    setValPtr(nullptr);
    Idx = 0;
    return;
  }
  
  // Otherwise, it is an entry in ScopeInlinedAtRecords, we don't know if it
  // is the scope or the inlined-at record entry.
  assert(unsigned(-Idx-1) < Ctx->ScopeInlinedAtRecords.size());
  std::pair<DebugRecVH, DebugRecVH> &Entry = Ctx->ScopeInlinedAtRecords[-Idx-1];
  assert((this == &Entry.first || this == &Entry.second) &&
         "Mapping out of date!");
  
  MDNode *OldScope = Entry.first.get();
  MDNode *OldInlinedAt = Entry.second.get();
  assert(OldScope && OldInlinedAt &&
         "Entry should be non-canonical if either val dropped to null");

  // Otherwise, we do have an entry in it, nuke it and we're done.
  assert(Ctx->ScopeInlinedAtIdx[std::make_pair(OldScope, OldInlinedAt)] == Idx&&
         "Mapping out of date");
  Ctx->ScopeInlinedAtIdx.erase(std::make_pair(OldScope, OldInlinedAt));
  
  // Reset this VH to null.  Drop both 'Idx' values to null to indicate that
  // we're in non-canonical form now.
  setValPtr(nullptr);
  Entry.first.Idx = Entry.second.Idx = 0;
}

void DebugRecVH::allUsesReplacedWith(Value *NewVa) {
  // If being replaced with a non-mdnode value (e.g. undef) handle this as if
  // the mdnode got deleted.
  MDNode *NewVal = dyn_cast<MDNode>(NewVa);
  if (!NewVal) return deleted();

  // If this is a non-canonical reference, just change it, we know it already
  // doesn't have a map entry.
  if (Idx == 0) {
    setValPtr(NewVa);
    return;
  }
  
  MDNode *OldVal = get();
  assert(OldVal != NewVa && "Node replaced with self?");
  
  // If the index is positive, it is an entry in ScopeRecords.
  if (Idx > 0) {
    assert(Ctx->ScopeRecordIdx[OldVal] == Idx && "Mapping out of date!");
    Ctx->ScopeRecordIdx.erase(OldVal);
    setValPtr(NewVal);

    int NewEntry = Ctx->getOrAddScopeRecordIdxEntry(NewVal, Idx);
    
    // If NewVal already has an entry, this becomes a non-canonical reference,
    // just drop Idx to 0 to signify this.
    if (NewEntry != Idx)
      Idx = 0;
    return;
  }
  
  // Otherwise, it is an entry in ScopeInlinedAtRecords, we don't know if it
  // is the scope or the inlined-at record entry.
  assert(unsigned(-Idx-1) < Ctx->ScopeInlinedAtRecords.size());
  std::pair<DebugRecVH, DebugRecVH> &Entry = Ctx->ScopeInlinedAtRecords[-Idx-1];
  assert((this == &Entry.first || this == &Entry.second) &&
         "Mapping out of date!");
  
  MDNode *OldScope = Entry.first.get();
  MDNode *OldInlinedAt = Entry.second.get();
  assert(OldScope && OldInlinedAt &&
         "Entry should be non-canonical if either val dropped to null");
  
  // Otherwise, we do have an entry in it, nuke it and we're done.
  assert(Ctx->ScopeInlinedAtIdx[std::make_pair(OldScope, OldInlinedAt)] == Idx&&
         "Mapping out of date");
  Ctx->ScopeInlinedAtIdx.erase(std::make_pair(OldScope, OldInlinedAt));
  
  // Reset this VH to the new value.
  setValPtr(NewVal);

  int NewIdx = Ctx->getOrAddScopeInlinedAtIdxEntry(Entry.first.get(),
                                                   Entry.second.get(), Idx);
  // If NewVal already has an entry, this becomes a non-canonical reference,
  // just drop Idx to 0 to signify this.
  if (NewIdx != Idx) {
    std::pair<DebugRecVH, DebugRecVH> &Entry=Ctx->ScopeInlinedAtRecords[-Idx-1];
    Entry.first.Idx = Entry.second.Idx = 0;
  }
}