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