xref: /freebsd/contrib/llvm-project/llvm/lib/IR/DebugLoc.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
10b57cec5SDimitry Andric //===-- DebugLoc.cpp - Implement DebugLoc class ---------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h"
100b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h"
110b57cec5SDimitry Andric #include "llvm/IR/DebugInfo.h"
120b57cec5SDimitry Andric using namespace llvm;
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
150b57cec5SDimitry Andric // DebugLoc Implementation
160b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
DebugLoc(const DILocation * L)170b57cec5SDimitry Andric DebugLoc::DebugLoc(const DILocation *L) : Loc(const_cast<DILocation *>(L)) {}
DebugLoc(const MDNode * L)180b57cec5SDimitry Andric DebugLoc::DebugLoc(const MDNode *L) : Loc(const_cast<MDNode *>(L)) {}
190b57cec5SDimitry Andric 
get() const200b57cec5SDimitry Andric DILocation *DebugLoc::get() const {
210b57cec5SDimitry Andric   return cast_or_null<DILocation>(Loc.get());
220b57cec5SDimitry Andric }
230b57cec5SDimitry Andric 
getLine() const240b57cec5SDimitry Andric unsigned DebugLoc::getLine() const {
250b57cec5SDimitry Andric   assert(get() && "Expected valid DebugLoc");
260b57cec5SDimitry Andric   return get()->getLine();
270b57cec5SDimitry Andric }
280b57cec5SDimitry Andric 
getCol() const290b57cec5SDimitry Andric unsigned DebugLoc::getCol() const {
300b57cec5SDimitry Andric   assert(get() && "Expected valid DebugLoc");
310b57cec5SDimitry Andric   return get()->getColumn();
320b57cec5SDimitry Andric }
330b57cec5SDimitry Andric 
getScope() const340b57cec5SDimitry Andric MDNode *DebugLoc::getScope() const {
350b57cec5SDimitry Andric   assert(get() && "Expected valid DebugLoc");
360b57cec5SDimitry Andric   return get()->getScope();
370b57cec5SDimitry Andric }
380b57cec5SDimitry Andric 
getInlinedAt() const390b57cec5SDimitry Andric DILocation *DebugLoc::getInlinedAt() const {
400b57cec5SDimitry Andric   assert(get() && "Expected valid DebugLoc");
410b57cec5SDimitry Andric   return get()->getInlinedAt();
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric 
getInlinedAtScope() const440b57cec5SDimitry Andric MDNode *DebugLoc::getInlinedAtScope() const {
450b57cec5SDimitry Andric   return cast<DILocation>(Loc)->getInlinedAtScope();
460b57cec5SDimitry Andric }
470b57cec5SDimitry Andric 
getFnDebugLoc() const480b57cec5SDimitry Andric DebugLoc DebugLoc::getFnDebugLoc() const {
490b57cec5SDimitry Andric   // FIXME: Add a method on \a DILocation that does this work.
500b57cec5SDimitry Andric   const MDNode *Scope = getInlinedAtScope();
510b57cec5SDimitry Andric   if (auto *SP = getDISubprogram(Scope))
52e8d8bef9SDimitry Andric     return DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP);
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   return DebugLoc();
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric 
isImplicitCode() const570b57cec5SDimitry Andric bool DebugLoc::isImplicitCode() const {
580b57cec5SDimitry Andric   if (DILocation *Loc = get()) {
590b57cec5SDimitry Andric     return Loc->isImplicitCode();
600b57cec5SDimitry Andric   }
610b57cec5SDimitry Andric   return true;
620b57cec5SDimitry Andric }
630b57cec5SDimitry Andric 
setImplicitCode(bool ImplicitCode)640b57cec5SDimitry Andric void DebugLoc::setImplicitCode(bool ImplicitCode) {
650b57cec5SDimitry Andric   if (DILocation *Loc = get()) {
660b57cec5SDimitry Andric     Loc->setImplicitCode(ImplicitCode);
670b57cec5SDimitry Andric   }
680b57cec5SDimitry Andric }
690b57cec5SDimitry Andric 
replaceInlinedAtSubprogram(const DebugLoc & RootLoc,DISubprogram & NewSP,LLVMContext & Ctx,DenseMap<const MDNode *,MDNode * > & Cache)70*bdd1243dSDimitry Andric DebugLoc DebugLoc::replaceInlinedAtSubprogram(
71*bdd1243dSDimitry Andric     const DebugLoc &RootLoc, DISubprogram &NewSP, LLVMContext &Ctx,
72*bdd1243dSDimitry Andric     DenseMap<const MDNode *, MDNode *> &Cache) {
73*bdd1243dSDimitry Andric   SmallVector<DILocation *> LocChain;
74*bdd1243dSDimitry Andric   DILocation *CachedResult = nullptr;
75*bdd1243dSDimitry Andric 
76*bdd1243dSDimitry Andric   // Collect the inline chain, stopping if we find a location that has already
77*bdd1243dSDimitry Andric   // been processed.
78*bdd1243dSDimitry Andric   for (DILocation *Loc = RootLoc; Loc; Loc = Loc->getInlinedAt()) {
79*bdd1243dSDimitry Andric     if (auto It = Cache.find(Loc); It != Cache.end()) {
80*bdd1243dSDimitry Andric       CachedResult = cast<DILocation>(It->second);
81*bdd1243dSDimitry Andric       break;
82*bdd1243dSDimitry Andric     }
83*bdd1243dSDimitry Andric     LocChain.push_back(Loc);
84*bdd1243dSDimitry Andric   }
85*bdd1243dSDimitry Andric 
86*bdd1243dSDimitry Andric   DILocation *UpdatedLoc = CachedResult;
87*bdd1243dSDimitry Andric   if (!UpdatedLoc) {
88*bdd1243dSDimitry Andric     // If no cache hits, then back() is the end of the inline chain, that is,
89*bdd1243dSDimitry Andric     // the DILocation whose scope ends in the Subprogram to be replaced.
90*bdd1243dSDimitry Andric     DILocation *LocToUpdate = LocChain.pop_back_val();
91*bdd1243dSDimitry Andric     DIScope *NewScope = DILocalScope::cloneScopeForSubprogram(
92*bdd1243dSDimitry Andric         *LocToUpdate->getScope(), NewSP, Ctx, Cache);
93*bdd1243dSDimitry Andric     UpdatedLoc = DILocation::get(Ctx, LocToUpdate->getLine(),
94*bdd1243dSDimitry Andric                                  LocToUpdate->getColumn(), NewScope);
95*bdd1243dSDimitry Andric     Cache[LocToUpdate] = UpdatedLoc;
96*bdd1243dSDimitry Andric   }
97*bdd1243dSDimitry Andric 
98*bdd1243dSDimitry Andric   // Recreate the location chain, bottom-up, starting at the new scope (or a
99*bdd1243dSDimitry Andric   // cached result).
100*bdd1243dSDimitry Andric   for (const DILocation *LocToUpdate : reverse(LocChain)) {
101*bdd1243dSDimitry Andric     UpdatedLoc =
102*bdd1243dSDimitry Andric         DILocation::get(Ctx, LocToUpdate->getLine(), LocToUpdate->getColumn(),
103*bdd1243dSDimitry Andric                         LocToUpdate->getScope(), UpdatedLoc);
104*bdd1243dSDimitry Andric     Cache[LocToUpdate] = UpdatedLoc;
105*bdd1243dSDimitry Andric   }
106*bdd1243dSDimitry Andric 
107*bdd1243dSDimitry Andric   return UpdatedLoc;
108*bdd1243dSDimitry Andric }
109*bdd1243dSDimitry Andric 
appendInlinedAt(const DebugLoc & DL,DILocation * InlinedAt,LLVMContext & Ctx,DenseMap<const MDNode *,MDNode * > & Cache)1105ffd83dbSDimitry Andric DebugLoc DebugLoc::appendInlinedAt(const DebugLoc &DL, DILocation *InlinedAt,
1110b57cec5SDimitry Andric                                    LLVMContext &Ctx,
112e8d8bef9SDimitry Andric                                    DenseMap<const MDNode *, MDNode *> &Cache) {
1130b57cec5SDimitry Andric   SmallVector<DILocation *, 3> InlinedAtLocations;
1140b57cec5SDimitry Andric   DILocation *Last = InlinedAt;
1150b57cec5SDimitry Andric   DILocation *CurInlinedAt = DL;
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   // Gather all the inlined-at nodes.
1180b57cec5SDimitry Andric   while (DILocation *IA = CurInlinedAt->getInlinedAt()) {
1190b57cec5SDimitry Andric     // Skip any we've already built nodes for.
1200b57cec5SDimitry Andric     if (auto *Found = Cache[IA]) {
1210b57cec5SDimitry Andric       Last = cast<DILocation>(Found);
1220b57cec5SDimitry Andric       break;
1230b57cec5SDimitry Andric     }
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric     InlinedAtLocations.push_back(IA);
1260b57cec5SDimitry Andric     CurInlinedAt = IA;
1270b57cec5SDimitry Andric   }
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric   // Starting from the top, rebuild the nodes to point to the new inlined-at
1300b57cec5SDimitry Andric   // location (then rebuilding the rest of the chain behind it) and update the
1310b57cec5SDimitry Andric   // map of already-constructed inlined-at nodes.
1320b57cec5SDimitry Andric   for (const DILocation *MD : reverse(InlinedAtLocations))
1330b57cec5SDimitry Andric     Cache[MD] = Last = DILocation::getDistinct(
1340b57cec5SDimitry Andric         Ctx, MD->getLine(), MD->getColumn(), MD->getScope(), Last);
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric   return Last;
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const1400b57cec5SDimitry Andric LLVM_DUMP_METHOD void DebugLoc::dump() const { print(dbgs()); }
1410b57cec5SDimitry Andric #endif
1420b57cec5SDimitry Andric 
print(raw_ostream & OS) const1430b57cec5SDimitry Andric void DebugLoc::print(raw_ostream &OS) const {
1440b57cec5SDimitry Andric   if (!Loc)
1450b57cec5SDimitry Andric     return;
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   // Print source line info.
1480b57cec5SDimitry Andric   auto *Scope = cast<DIScope>(getScope());
1490b57cec5SDimitry Andric   OS << Scope->getFilename();
1500b57cec5SDimitry Andric   OS << ':' << getLine();
1510b57cec5SDimitry Andric   if (getCol() != 0)
1520b57cec5SDimitry Andric     OS << ':' << getCol();
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   if (DebugLoc InlinedAtDL = getInlinedAt()) {
1550b57cec5SDimitry Andric     OS << " @[ ";
1560b57cec5SDimitry Andric     InlinedAtDL.print(OS);
1570b57cec5SDimitry Andric     OS << " ]";
1580b57cec5SDimitry Andric   }
1590b57cec5SDimitry Andric }
160