1 //===- LexicalScopes.cpp - Collecting lexical scope info ------------------===//
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 // This file implements LexicalScopes analysis.
10 //
11 // This pass collects lexical scope information and maps machine instructions
12 // to respective lexical scopes.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #include "llvm/CodeGen/LexicalScopes.h"
17 #include "llvm/ADT/DenseMap.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/CodeGen/MachineBasicBlock.h"
20 #include "llvm/CodeGen/MachineFunction.h"
21 #include "llvm/CodeGen/MachineInstr.h"
22 #include "llvm/Config/llvm-config.h"
23 #include "llvm/IR/DebugInfoMetadata.h"
24 #include "llvm/IR/Function.h"
25 #include "llvm/IR/Metadata.h"
26 #include "llvm/Support/Casting.h"
27 #include "llvm/Support/Compiler.h"
28 #include "llvm/Support/Debug.h"
29 #include "llvm/Support/raw_ostream.h"
30 #include <cassert>
31 #include <string>
32 #include <tuple>
33 #include <utility>
34
35 using namespace llvm;
36
37 #define DEBUG_TYPE "lexicalscopes"
38
39 /// reset - Reset the instance so that it's prepared for another function.
reset()40 void LexicalScopes::reset() {
41 MF = nullptr;
42 CurrentFnLexicalScope = nullptr;
43 LexicalScopeMap.clear();
44 AbstractScopeMap.clear();
45 InlinedLexicalScopeMap.clear();
46 AbstractScopesList.clear();
47 }
48
49 /// initialize - Scan machine function and constuct lexical scope nest.
initialize(const MachineFunction & Fn)50 void LexicalScopes::initialize(const MachineFunction &Fn) {
51 reset();
52 // Don't attempt any lexical scope creation for a NoDebug compile unit.
53 if (Fn.getFunction().getSubprogram()->getUnit()->getEmissionKind() ==
54 DICompileUnit::NoDebug)
55 return;
56 MF = &Fn;
57 SmallVector<InsnRange, 4> MIRanges;
58 DenseMap<const MachineInstr *, LexicalScope *> MI2ScopeMap;
59 extractLexicalScopes(MIRanges, MI2ScopeMap);
60 if (CurrentFnLexicalScope) {
61 constructScopeNest(CurrentFnLexicalScope);
62 assignInstructionRanges(MIRanges, MI2ScopeMap);
63 }
64 }
65
66 /// extractLexicalScopes - Extract instruction ranges for each lexical scopes
67 /// for the given machine function.
extractLexicalScopes(SmallVectorImpl<InsnRange> & MIRanges,DenseMap<const MachineInstr *,LexicalScope * > & MI2ScopeMap)68 void LexicalScopes::extractLexicalScopes(
69 SmallVectorImpl<InsnRange> &MIRanges,
70 DenseMap<const MachineInstr *, LexicalScope *> &MI2ScopeMap) {
71 // Scan each instruction and create scopes. First build working set of scopes.
72 for (const auto &MBB : *MF) {
73 const MachineInstr *RangeBeginMI = nullptr;
74 const MachineInstr *PrevMI = nullptr;
75 const DILocation *PrevDL = nullptr;
76 for (const auto &MInsn : MBB) {
77 // Check if instruction has valid location information.
78 const DILocation *MIDL = MInsn.getDebugLoc();
79 if (!MIDL) {
80 PrevMI = &MInsn;
81 continue;
82 }
83
84 // If scope has not changed then skip this instruction.
85 if (MIDL == PrevDL) {
86 PrevMI = &MInsn;
87 continue;
88 }
89
90 // Ignore DBG_VALUE and similar instruction that do not contribute to any
91 // instruction in the output.
92 if (MInsn.isMetaInstruction())
93 continue;
94
95 if (RangeBeginMI) {
96 // If we have already seen a beginning of an instruction range and
97 // current instruction scope does not match scope of first instruction
98 // in this range then create a new instruction range.
99 InsnRange R(RangeBeginMI, PrevMI);
100 MI2ScopeMap[RangeBeginMI] = getOrCreateLexicalScope(PrevDL);
101 MIRanges.push_back(R);
102 }
103
104 // This is a beginning of a new instruction range.
105 RangeBeginMI = &MInsn;
106
107 // Reset previous markers.
108 PrevMI = &MInsn;
109 PrevDL = MIDL;
110 }
111
112 // Create last instruction range.
113 if (RangeBeginMI && PrevMI && PrevDL) {
114 InsnRange R(RangeBeginMI, PrevMI);
115 MIRanges.push_back(R);
116 MI2ScopeMap[RangeBeginMI] = getOrCreateLexicalScope(PrevDL);
117 }
118 }
119 }
120
121 /// findLexicalScope - Find lexical scope, either regular or inlined, for the
122 /// given DebugLoc. Return NULL if not found.
findLexicalScope(const DILocation * DL)123 LexicalScope *LexicalScopes::findLexicalScope(const DILocation *DL) {
124 DILocalScope *Scope = DL->getScope();
125 if (!Scope)
126 return nullptr;
127
128 // The scope that we were created with could have an extra file - which
129 // isn't what we care about in this case.
130 Scope = Scope->getNonLexicalBlockFileScope();
131
132 if (auto *IA = DL->getInlinedAt()) {
133 auto I = InlinedLexicalScopeMap.find(std::make_pair(Scope, IA));
134 return I != InlinedLexicalScopeMap.end() ? &I->second : nullptr;
135 }
136 return findLexicalScope(Scope);
137 }
138
139 /// getOrCreateLexicalScope - Find lexical scope for the given DebugLoc. If
140 /// not available then create new lexical scope.
getOrCreateLexicalScope(const DILocalScope * Scope,const DILocation * IA)141 LexicalScope *LexicalScopes::getOrCreateLexicalScope(const DILocalScope *Scope,
142 const DILocation *IA) {
143 if (IA) {
144 // Skip scopes inlined from a NoDebug compile unit.
145 if (Scope->getSubprogram()->getUnit()->getEmissionKind() ==
146 DICompileUnit::NoDebug)
147 return getOrCreateLexicalScope(IA);
148 // Create an abstract scope for inlined function.
149 getOrCreateAbstractScope(Scope);
150 // Create an inlined scope for inlined function.
151 return getOrCreateInlinedScope(Scope, IA);
152 }
153
154 return getOrCreateRegularScope(Scope);
155 }
156
157 /// getOrCreateRegularScope - Find or create a regular lexical scope.
158 LexicalScope *
getOrCreateRegularScope(const DILocalScope * Scope)159 LexicalScopes::getOrCreateRegularScope(const DILocalScope *Scope) {
160 assert(Scope && "Invalid Scope encoding!");
161 Scope = Scope->getNonLexicalBlockFileScope();
162
163 auto I = LexicalScopeMap.find(Scope);
164 if (I != LexicalScopeMap.end())
165 return &I->second;
166
167 // FIXME: Should the following dyn_cast be DILexicalBlock?
168 LexicalScope *Parent = nullptr;
169 if (auto *Block = dyn_cast<DILexicalBlockBase>(Scope))
170 Parent = getOrCreateLexicalScope(Block->getScope());
171 I = LexicalScopeMap.emplace(std::piecewise_construct,
172 std::forward_as_tuple(Scope),
173 std::forward_as_tuple(Parent, Scope, nullptr,
174 false)).first;
175
176 if (!Parent) {
177 assert(cast<DISubprogram>(Scope)->describes(&MF->getFunction()));
178 assert(!CurrentFnLexicalScope);
179 CurrentFnLexicalScope = &I->second;
180 }
181
182 return &I->second;
183 }
184
185 /// getOrCreateInlinedScope - Find or create an inlined lexical scope.
186 LexicalScope *
getOrCreateInlinedScope(const DILocalScope * Scope,const DILocation * InlinedAt)187 LexicalScopes::getOrCreateInlinedScope(const DILocalScope *Scope,
188 const DILocation *InlinedAt) {
189 assert(Scope && "Invalid Scope encoding!");
190 Scope = Scope->getNonLexicalBlockFileScope();
191 std::pair<const DILocalScope *, const DILocation *> P(Scope, InlinedAt);
192 auto I = InlinedLexicalScopeMap.find(P);
193 if (I != InlinedLexicalScopeMap.end())
194 return &I->second;
195
196 LexicalScope *Parent;
197 if (auto *Block = dyn_cast<DILexicalBlockBase>(Scope))
198 Parent = getOrCreateInlinedScope(Block->getScope(), InlinedAt);
199 else
200 Parent = getOrCreateLexicalScope(InlinedAt);
201
202 I = InlinedLexicalScopeMap
203 .emplace(std::piecewise_construct, std::forward_as_tuple(P),
204 std::forward_as_tuple(Parent, Scope, InlinedAt, false))
205 .first;
206 return &I->second;
207 }
208
209 /// getOrCreateAbstractScope - Find or create an abstract lexical scope.
210 LexicalScope *
getOrCreateAbstractScope(const DILocalScope * Scope)211 LexicalScopes::getOrCreateAbstractScope(const DILocalScope *Scope) {
212 assert(Scope && "Invalid Scope encoding!");
213 Scope = Scope->getNonLexicalBlockFileScope();
214 auto I = AbstractScopeMap.find(Scope);
215 if (I != AbstractScopeMap.end())
216 return &I->second;
217
218 // FIXME: Should the following isa be DILexicalBlock?
219 LexicalScope *Parent = nullptr;
220 if (auto *Block = dyn_cast<DILexicalBlockBase>(Scope))
221 Parent = getOrCreateAbstractScope(Block->getScope());
222
223 I = AbstractScopeMap.emplace(std::piecewise_construct,
224 std::forward_as_tuple(Scope),
225 std::forward_as_tuple(Parent, Scope,
226 nullptr, true)).first;
227 if (isa<DISubprogram>(Scope))
228 AbstractScopesList.push_back(&I->second);
229 return &I->second;
230 }
231
232 /// constructScopeNest
constructScopeNest(LexicalScope * Scope)233 void LexicalScopes::constructScopeNest(LexicalScope *Scope) {
234 assert(Scope && "Unable to calculate scope dominance graph!");
235 SmallVector<LexicalScope *, 4> WorkStack;
236 WorkStack.push_back(Scope);
237 unsigned Counter = 0;
238 while (!WorkStack.empty()) {
239 LexicalScope *WS = WorkStack.back();
240 const SmallVectorImpl<LexicalScope *> &Children = WS->getChildren();
241 bool visitedChildren = false;
242 for (auto &ChildScope : Children)
243 if (!ChildScope->getDFSOut()) {
244 WorkStack.push_back(ChildScope);
245 visitedChildren = true;
246 ChildScope->setDFSIn(++Counter);
247 break;
248 }
249 if (!visitedChildren) {
250 WorkStack.pop_back();
251 WS->setDFSOut(++Counter);
252 }
253 }
254 }
255
256 /// assignInstructionRanges - Find ranges of instructions covered by each
257 /// lexical scope.
assignInstructionRanges(SmallVectorImpl<InsnRange> & MIRanges,DenseMap<const MachineInstr *,LexicalScope * > & MI2ScopeMap)258 void LexicalScopes::assignInstructionRanges(
259 SmallVectorImpl<InsnRange> &MIRanges,
260 DenseMap<const MachineInstr *, LexicalScope *> &MI2ScopeMap) {
261 LexicalScope *PrevLexicalScope = nullptr;
262 for (const auto &R : MIRanges) {
263 LexicalScope *S = MI2ScopeMap.lookup(R.first);
264 assert(S && "Lost LexicalScope for a machine instruction!");
265 if (PrevLexicalScope && !PrevLexicalScope->dominates(S))
266 PrevLexicalScope->closeInsnRange(S);
267 S->openInsnRange(R.first);
268 S->extendInsnRange(R.second);
269 PrevLexicalScope = S;
270 }
271
272 if (PrevLexicalScope)
273 PrevLexicalScope->closeInsnRange();
274 }
275
276 /// getMachineBasicBlocks - Populate given set using machine basic blocks which
277 /// have machine instructions that belong to lexical scope identified by
278 /// DebugLoc.
getMachineBasicBlocks(const DILocation * DL,SmallPtrSetImpl<const MachineBasicBlock * > & MBBs)279 void LexicalScopes::getMachineBasicBlocks(
280 const DILocation *DL, SmallPtrSetImpl<const MachineBasicBlock *> &MBBs) {
281 assert(MF && "Method called on a uninitialized LexicalScopes object!");
282 MBBs.clear();
283
284 LexicalScope *Scope = getOrCreateLexicalScope(DL);
285 if (!Scope)
286 return;
287
288 if (Scope == CurrentFnLexicalScope) {
289 for (const auto &MBB : *MF)
290 MBBs.insert(&MBB);
291 return;
292 }
293
294 SmallVectorImpl<InsnRange> &InsnRanges = Scope->getRanges();
295 for (auto &R : InsnRanges)
296 MBBs.insert(R.first->getParent());
297 }
298
299 /// dominates - Return true if DebugLoc's lexical scope dominates at least one
300 /// machine instruction's lexical scope in a given machine basic block.
dominates(const DILocation * DL,MachineBasicBlock * MBB)301 bool LexicalScopes::dominates(const DILocation *DL, MachineBasicBlock *MBB) {
302 assert(MF && "Unexpected uninitialized LexicalScopes object!");
303 LexicalScope *Scope = getOrCreateLexicalScope(DL);
304 if (!Scope)
305 return false;
306
307 // Current function scope covers all basic blocks in the function.
308 if (Scope == CurrentFnLexicalScope && MBB->getParent() == MF)
309 return true;
310
311 bool Result = false;
312 for (auto &I : *MBB) {
313 if (const DILocation *IDL = I.getDebugLoc())
314 if (LexicalScope *IScope = getOrCreateLexicalScope(IDL))
315 if (Scope->dominates(IScope))
316 return true;
317 }
318 return Result;
319 }
320
321 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump(unsigned Indent) const322 LLVM_DUMP_METHOD void LexicalScope::dump(unsigned Indent) const {
323 raw_ostream &err = dbgs();
324 err.indent(Indent);
325 err << "DFSIn: " << DFSIn << " DFSOut: " << DFSOut << "\n";
326 const MDNode *N = Desc;
327 err.indent(Indent);
328 N->dump();
329 if (AbstractScope)
330 err << std::string(Indent, ' ') << "Abstract Scope\n";
331
332 if (!Children.empty())
333 err << std::string(Indent + 2, ' ') << "Children ...\n";
334 for (unsigned i = 0, e = Children.size(); i != e; ++i)
335 if (Children[i] != this)
336 Children[i]->dump(Indent + 2);
337 }
338 #endif
339