57a0990e61
This utility will be useful in subsequent patches, as such we expose it in the DebugInfoMetadata header. Depends on D139669 Differential Revision: https://reviews.llvm.org/D139670
160 lines
4.9 KiB
C++
160 lines
4.9 KiB
C++
//===-- 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 << " ]";
|
|
}
|
|
}
|