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