1 //===-- DebugLoc.cpp - Implement DebugLoc class ---------------------------===//
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 #include "llvm/IR/DebugLoc.h"
10 #include "llvm/Config/llvm-config.h"
11 #include "llvm/IR/DebugInfo.h"
12
13 #if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
14 #include "llvm/Support/Signals.h"
15
16 namespace llvm {
DbgLocOrigin(bool ShouldCollectTrace)17 DbgLocOrigin::DbgLocOrigin(bool ShouldCollectTrace) {
18 if (!ShouldCollectTrace)
19 return;
20 auto &[Depth, StackTrace] = StackTraces.emplace_back();
21 Depth = sys::getStackTrace(StackTrace);
22 }
addTrace()23 void DbgLocOrigin::addTrace() {
24 // We only want to add new stacktraces if we already have one: addTrace exists
25 // to provide more context to how missing DebugLocs have propagated through
26 // the program, but by design if there is no existing stacktrace then we have
27 // decided not to track this DebugLoc as being "missing".
28 if (StackTraces.empty())
29 return;
30 auto &[Depth, StackTrace] = StackTraces.emplace_back();
31 Depth = sys::getStackTrace(StackTrace);
32 }
33 } // namespace llvm
34 #endif
35
36 using namespace llvm;
37
38 #if LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE
DILocAndCoverageTracking(const DILocation * L)39 DILocAndCoverageTracking::DILocAndCoverageTracking(const DILocation *L)
40 : TrackingMDNodeRef(const_cast<DILocation *>(L)), DbgLocOrigin(!L),
41 Kind(DebugLocKind::Normal) {}
42 #endif // LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE
43
44 //===----------------------------------------------------------------------===//
45 // DebugLoc Implementation
46 //===----------------------------------------------------------------------===//
DebugLoc(const DILocation * L)47 DebugLoc::DebugLoc(const DILocation *L) : Loc(const_cast<DILocation *>(L)) {}
DebugLoc(const MDNode * L)48 DebugLoc::DebugLoc(const MDNode *L) : Loc(const_cast<MDNode *>(L)) {}
49
get() const50 DILocation *DebugLoc::get() const {
51 return cast_or_null<DILocation>(Loc.get());
52 }
53
getLine() const54 unsigned DebugLoc::getLine() const {
55 assert(get() && "Expected valid DebugLoc");
56 return get()->getLine();
57 }
58
getCol() const59 unsigned DebugLoc::getCol() const {
60 assert(get() && "Expected valid DebugLoc");
61 return get()->getColumn();
62 }
63
getScope() const64 MDNode *DebugLoc::getScope() const {
65 assert(get() && "Expected valid DebugLoc");
66 return get()->getScope();
67 }
68
getInlinedAt() const69 DILocation *DebugLoc::getInlinedAt() const {
70 assert(get() && "Expected valid DebugLoc");
71 return get()->getInlinedAt();
72 }
73
getInlinedAtScope() const74 MDNode *DebugLoc::getInlinedAtScope() const {
75 return cast<DILocation>(Loc)->getInlinedAtScope();
76 }
77
getFnDebugLoc() const78 DebugLoc DebugLoc::getFnDebugLoc() const {
79 // FIXME: Add a method on \a DILocation that does this work.
80 const MDNode *Scope = getInlinedAtScope();
81 if (auto *SP = getDISubprogram(Scope))
82 return DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP);
83
84 return DebugLoc();
85 }
86
isImplicitCode() const87 bool DebugLoc::isImplicitCode() const {
88 if (DILocation *Loc = get()) {
89 return Loc->isImplicitCode();
90 }
91 return true;
92 }
93
setImplicitCode(bool ImplicitCode)94 void DebugLoc::setImplicitCode(bool ImplicitCode) {
95 if (DILocation *Loc = get()) {
96 Loc->setImplicitCode(ImplicitCode);
97 }
98 }
99
replaceInlinedAtSubprogram(const DebugLoc & RootLoc,DISubprogram & NewSP,LLVMContext & Ctx,DenseMap<const MDNode *,MDNode * > & Cache)100 DebugLoc DebugLoc::replaceInlinedAtSubprogram(
101 const DebugLoc &RootLoc, DISubprogram &NewSP, LLVMContext &Ctx,
102 DenseMap<const MDNode *, MDNode *> &Cache) {
103 SmallVector<DILocation *> LocChain;
104 DILocation *CachedResult = nullptr;
105
106 // Collect the inline chain, stopping if we find a location that has already
107 // been processed.
108 for (DILocation *Loc = RootLoc; Loc; Loc = Loc->getInlinedAt()) {
109 if (auto It = Cache.find(Loc); It != Cache.end()) {
110 CachedResult = cast<DILocation>(It->second);
111 break;
112 }
113 LocChain.push_back(Loc);
114 }
115
116 DILocation *UpdatedLoc = CachedResult;
117 if (!UpdatedLoc) {
118 // If no cache hits, then back() is the end of the inline chain, that is,
119 // the DILocation whose scope ends in the Subprogram to be replaced.
120 DILocation *LocToUpdate = LocChain.pop_back_val();
121 DIScope *NewScope = DILocalScope::cloneScopeForSubprogram(
122 *LocToUpdate->getScope(), NewSP, Ctx, Cache);
123 UpdatedLoc = DILocation::get(Ctx, LocToUpdate->getLine(),
124 LocToUpdate->getColumn(), NewScope);
125 Cache[LocToUpdate] = UpdatedLoc;
126 }
127
128 // Recreate the location chain, bottom-up, starting at the new scope (or a
129 // cached result).
130 for (const DILocation *LocToUpdate : reverse(LocChain)) {
131 UpdatedLoc =
132 DILocation::get(Ctx, LocToUpdate->getLine(), LocToUpdate->getColumn(),
133 LocToUpdate->getScope(), UpdatedLoc);
134 Cache[LocToUpdate] = UpdatedLoc;
135 }
136
137 return UpdatedLoc;
138 }
139
appendInlinedAt(const DebugLoc & DL,DILocation * InlinedAt,LLVMContext & Ctx,DenseMap<const MDNode *,MDNode * > & Cache)140 DebugLoc DebugLoc::appendInlinedAt(const DebugLoc &DL, DILocation *InlinedAt,
141 LLVMContext &Ctx,
142 DenseMap<const MDNode *, MDNode *> &Cache) {
143 SmallVector<DILocation *, 3> InlinedAtLocations;
144 DILocation *Last = InlinedAt;
145 DILocation *CurInlinedAt = DL;
146
147 // Gather all the inlined-at nodes.
148 while (DILocation *IA = CurInlinedAt->getInlinedAt()) {
149 // Skip any we've already built nodes for.
150 if (auto *Found = Cache[IA]) {
151 Last = cast<DILocation>(Found);
152 break;
153 }
154
155 InlinedAtLocations.push_back(IA);
156 CurInlinedAt = IA;
157 }
158
159 // Starting from the top, rebuild the nodes to point to the new inlined-at
160 // location (then rebuilding the rest of the chain behind it) and update the
161 // map of already-constructed inlined-at nodes.
162 // Key Instructions: InlinedAt fields don't need atom info.
163 for (const DILocation *MD : reverse(InlinedAtLocations))
164 Cache[MD] = Last = DILocation::getDistinct(
165 Ctx, MD->getLine(), MD->getColumn(), MD->getScope(), Last);
166
167 return Last;
168 }
169
getMergedLocations(ArrayRef<DebugLoc> Locs)170 DebugLoc DebugLoc::getMergedLocations(ArrayRef<DebugLoc> Locs) {
171 if (Locs.empty())
172 return DebugLoc();
173 if (Locs.size() == 1)
174 return Locs[0];
175 DebugLoc Merged = Locs[0];
176 for (const DebugLoc &DL : llvm::drop_begin(Locs)) {
177 Merged = getMergedLocation(Merged, DL);
178 if (!Merged)
179 break;
180 }
181 return Merged;
182 }
getMergedLocation(DebugLoc LocA,DebugLoc LocB)183 DebugLoc DebugLoc::getMergedLocation(DebugLoc LocA, DebugLoc LocB) {
184 if (!LocA)
185 return LocA;
186 if (!LocB)
187 return LocB;
188 return DILocation::getMergedLocation(LocA, LocB);
189 }
190
191 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const192 LLVM_DUMP_METHOD void DebugLoc::dump() const { print(dbgs()); }
193 #endif
194
print(raw_ostream & OS) const195 void DebugLoc::print(raw_ostream &OS) const {
196 if (!Loc)
197 return;
198
199 // Print source line info.
200 auto *Scope = cast<DIScope>(getScope());
201 OS << Scope->getFilename();
202 OS << ':' << getLine();
203 if (getCol() != 0)
204 OS << ':' << getCol();
205
206 if (DebugLoc InlinedAtDL = getInlinedAt()) {
207 OS << " @[ ";
208 InlinedAtDL.print(OS);
209 OS << " ]";
210 }
211 }
212