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