| //===-- DebugLoc.cpp - Implement DebugLoc class ---------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/IR/DebugLoc.h" | |
| #include "llvm/Config/llvm-config.h" | |
| #include "llvm/IR/DebugInfo.h" | |
| using namespace llvm; | |
| //===----------------------------------------------------------------------===// | |
| // DebugLoc Implementation | |
| //===----------------------------------------------------------------------===// | |
| DebugLoc::DebugLoc(const DILocation *L) : Loc(const_cast<DILocation *>(L)) {} | |
| DebugLoc::DebugLoc(const MDNode *L) : Loc(const_cast<MDNode *>(L)) {} | |
| DILocation *DebugLoc::get() const { | |
| return cast_or_null<DILocation>(Loc.get()); | |
| } | |
| unsigned DebugLoc::getLine() const { | |
| assert(get() && "Expected valid DebugLoc"); | |
| return get()->getLine(); | |
| } | |
| unsigned DebugLoc::getCol() const { | |
| assert(get() && "Expected valid DebugLoc"); | |
| return get()->getColumn(); | |
| } | |
| MDNode *DebugLoc::getScope() const { | |
| assert(get() && "Expected valid DebugLoc"); | |
| return get()->getScope(); | |
| } | |
| DILocation *DebugLoc::getInlinedAt() const { | |
| assert(get() && "Expected valid DebugLoc"); | |
| return get()->getInlinedAt(); | |
| } | |
| MDNode *DebugLoc::getInlinedAtScope() const { | |
| return cast<DILocation>(Loc)->getInlinedAtScope(); | |
| } | |
| DebugLoc DebugLoc::getFnDebugLoc() const { | |
| // FIXME: Add a method on \a DILocation that does this work. | |
| const MDNode *Scope = getInlinedAtScope(); | |
| if (auto *SP = getDISubprogram(Scope)) | |
| return DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP); | |
| return DebugLoc(); | |
| } | |
| bool DebugLoc::isImplicitCode() const { | |
| if (DILocation *Loc = get()) { | |
| return Loc->isImplicitCode(); | |
| } | |
| return true; | |
| } | |
| void DebugLoc::setImplicitCode(bool ImplicitCode) { | |
| if (DILocation *Loc = get()) { | |
| Loc->setImplicitCode(ImplicitCode); | |
| } | |
| } | |
| DebugLoc DebugLoc::replaceInlinedAtSubprogram( | |
| const DebugLoc &RootLoc, DISubprogram &NewSP, LLVMContext &Ctx, | |
| DenseMap<const MDNode *, MDNode *> &Cache) { | |
| SmallVector<DILocation *> LocChain; | |
| DILocation *CachedResult = nullptr; | |
| // Collect the inline chain, stopping if we find a location that has already | |
| // been processed. | |
| for (DILocation *Loc = RootLoc; Loc; Loc = Loc->getInlinedAt()) { | |
| if (auto It = Cache.find(Loc); It != Cache.end()) { | |
| CachedResult = cast<DILocation>(It->second); | |
| break; | |
| } | |
| LocChain.push_back(Loc); | |
| } | |
| DILocation *UpdatedLoc = CachedResult; | |
| if (!UpdatedLoc) { | |
| // If no cache hits, then back() is the end of the inline chain, that is, | |
| // the DILocation whose scope ends in the Subprogram to be replaced. | |
| DILocation *LocToUpdate = LocChain.pop_back_val(); | |
| DIScope *NewScope = DILocalScope::cloneScopeForSubprogram( | |
| *LocToUpdate->getScope(), NewSP, Ctx, Cache); | |
| UpdatedLoc = DILocation::get(Ctx, LocToUpdate->getLine(), | |
| LocToUpdate->getColumn(), NewScope); | |
| Cache[LocToUpdate] = UpdatedLoc; | |
| } | |
| // Recreate the location chain, bottom-up, starting at the new scope (or a | |
| // cached result). | |
| for (const DILocation *LocToUpdate : reverse(LocChain)) { | |
| UpdatedLoc = | |
| DILocation::get(Ctx, LocToUpdate->getLine(), LocToUpdate->getColumn(), | |
| LocToUpdate->getScope(), UpdatedLoc); | |
| Cache[LocToUpdate] = UpdatedLoc; | |
| } | |
| return UpdatedLoc; | |
| } | |
| DebugLoc DebugLoc::appendInlinedAt(const DebugLoc &DL, DILocation *InlinedAt, | |
| LLVMContext &Ctx, | |
| DenseMap<const MDNode *, MDNode *> &Cache) { | |
| SmallVector<DILocation *, 3> InlinedAtLocations; | |
| DILocation *Last = InlinedAt; | |
| DILocation *CurInlinedAt = DL; | |
| // Gather all the inlined-at nodes. | |
| while (DILocation *IA = CurInlinedAt->getInlinedAt()) { | |
| // Skip any we've already built nodes for. | |
| if (auto *Found = Cache[IA]) { | |
| Last = cast<DILocation>(Found); | |
| break; | |
| } | |
| InlinedAtLocations.push_back(IA); | |
| CurInlinedAt = IA; | |
| } | |
| // Starting from the top, rebuild the nodes to point to the new inlined-at | |
| // location (then rebuilding the rest of the chain behind it) and update the | |
| // map of already-constructed inlined-at nodes. | |
| for (const DILocation *MD : reverse(InlinedAtLocations)) | |
| Cache[MD] = Last = DILocation::getDistinct( | |
| Ctx, MD->getLine(), MD->getColumn(), MD->getScope(), Last); | |
| return Last; | |
| } | |
| #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | |
| LLVM_DUMP_METHOD void DebugLoc::dump() const { print(dbgs()); } | |
| #endif | |
| void DebugLoc::print(raw_ostream &OS) const { | |
| if (!Loc) | |
| return; | |
| // Print source line info. | |
| auto *Scope = cast<DIScope>(getScope()); | |
| OS << Scope->getFilename(); | |
| OS << ':' << getLine(); | |
| if (getCol() != 0) | |
| OS << ':' << getCol(); | |
| if (DebugLoc InlinedAtDL = getInlinedAt()) { | |
| OS << " @[ "; | |
| InlinedAtDL.print(OS); | |
| OS << " ]"; | |
| } | |
| } |