diff options
| author | Adrian Prantl <aprantl@apple.com> | 2017-05-09 19:47:37 +0000 |
|---|---|---|
| committer | Adrian Prantl <aprantl@apple.com> | 2017-05-09 19:47:37 +0000 |
| commit | c10d0e5ccd12f049bddb24dcf8bbb7fbbc6c68f2 (patch) | |
| tree | 040042696a2447b6326e2086d645a95c5eca8954 /llvm/lib/IR | |
| parent | d979c1f80607eabadf8395ac690daf1b93f24789 (diff) | |
| download | bcm5719-llvm-c10d0e5ccd12f049bddb24dcf8bbb7fbbc6c68f2.tar.gz bcm5719-llvm-c10d0e5ccd12f049bddb24dcf8bbb7fbbc6c68f2.zip | |
Make it illegal for two Functions to point to the same DISubprogram
As recently discussed on llvm-dev [1], this patch makes it illegal for
two Functions to point to the same DISubprogram and updates
FunctionCloner to also clone the debug info of a function to conform
to the new requirement. To simplify the implementation it also factors
out the creation of inlineAt locations from the Inliner into a
general-purpose utility in DILocation.
[1] http://lists.llvm.org/pipermail/llvm-dev/2017-May/112661.html
<rdar://problem/31926379>
Differential Revision: https://reviews.llvm.org/D32975
This reapplies r302469 with a fix for a bot failure (reparentDebugInfo
now checks for the case the orig and new function are identical).
llvm-svn: 302576
Diffstat (limited to 'llvm/lib/IR')
| -rw-r--r-- | llvm/lib/IR/DebugLoc.cpp | 114 | ||||
| -rw-r--r-- | llvm/lib/IR/Verifier.cpp | 13 |
2 files changed, 125 insertions, 2 deletions
diff --git a/llvm/lib/IR/DebugLoc.cpp b/llvm/lib/IR/DebugLoc.cpp index f31074a7ad4..3168ec6944a 100644 --- a/llvm/lib/IR/DebugLoc.cpp +++ b/llvm/lib/IR/DebugLoc.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/DebugLoc.h" +#include "llvm/IR/IntrinsicInst.h" #include "LLVMContextImpl.h" #include "llvm/IR/DebugInfo.h" using namespace llvm; @@ -66,6 +67,119 @@ DebugLoc DebugLoc::get(unsigned Line, unsigned Col, const MDNode *Scope, const_cast<MDNode *>(InlinedAt)); } +DebugLoc DebugLoc::appendInlinedAt(DebugLoc DL, DILocation *InlinedAt, + LLVMContext &Ctx, + DenseMap<const MDNode *, MDNode *> &Cache, + bool ReplaceLast) { + 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; + } + + if (ReplaceLast && !IA->getInlinedAt()) + 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; +} + +/// Reparent \c Scope from \c OrigSP to \c NewSP. +static DIScope *reparentScope(LLVMContext &Ctx, DIScope *Scope, + DISubprogram *OrigSP, DISubprogram *NewSP, + DenseMap<const MDNode *, MDNode *> &Cache) { + SmallVector<DIScope *, 3> ScopeChain; + DIScope *Last = NewSP; + DIScope *CurScope = Scope; + do { + if (auto *SP = dyn_cast<DISubprogram>(CurScope)) { + // Don't rewrite this scope chain if it doesn't lead to the replaced SP. + if (SP != OrigSP) + return Scope; + Cache.insert({OrigSP, NewSP}); + break; + } + if (auto *Found = Cache[CurScope]) { + Last = cast<DIScope>(Found); + break; + } + ScopeChain.push_back(CurScope); + } while ((CurScope = CurScope->getScope().resolve())); + + // 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 DIScope *MD : reverse(ScopeChain)) { + if (auto *LB = dyn_cast<DILexicalBlock>(MD)) + Cache[MD] = Last = DILexicalBlock::getDistinct( + Ctx, Last, LB->getFile(), LB->getLine(), LB->getColumn()); + else if (auto *LB = dyn_cast<DILexicalBlockFile>(MD)) + Cache[MD] = Last = DILexicalBlockFile::getDistinct( + Ctx, Last, LB->getFile(), LB->getDiscriminator()); + else + llvm_unreachable("illegal parent scope"); + } + return Last; +} + +void DebugLoc::reparentDebugInfo(Instruction &I, DISubprogram *OrigSP, + DISubprogram *NewSP, + DenseMap<const MDNode *, MDNode *> &Cache) { + auto DL = I.getDebugLoc(); + if (!OrigSP || !NewSP || OrigSP == NewSP || !DL) + return; + + // Reparent the debug location. + auto &Ctx = I.getContext(); + DILocation *InlinedAt = DL->getInlinedAt(); + if (InlinedAt) { + while (auto *IA = InlinedAt->getInlinedAt()) + InlinedAt = IA; + auto NewScope = + reparentScope(Ctx, InlinedAt->getScope(), OrigSP, NewSP, Cache); + InlinedAt = + DebugLoc::get(InlinedAt->getLine(), InlinedAt->getColumn(), NewScope); + } + I.setDebugLoc( + DebugLoc::get(DL.getLine(), DL.getCol(), + reparentScope(Ctx, DL->getScope(), OrigSP, NewSP, Cache), + DebugLoc::appendInlinedAt(DL, InlinedAt, Ctx, Cache, + ReplaceLastInlinedAt))); + + // Fix up debug variables to point to NewSP. + auto reparentVar = [&](DILocalVariable *Var) { + return DILocalVariable::getDistinct( + Ctx, + cast<DILocalScope>( + reparentScope(Ctx, Var->getScope(), OrigSP, NewSP, Cache)), + Var->getName(), Var->getFile(), Var->getLine(), Var->getType(), + Var->getArg(), Var->getFlags(), Var->getAlignInBits()); + }; + if (auto *DbgValue = dyn_cast<DbgValueInst>(&I)) { + auto *Var = DbgValue->getVariable(); + I.setOperand(2, MetadataAsValue::get(Ctx, reparentVar(Var))); + } else if (auto *DbgDeclare = dyn_cast<DbgDeclareInst>(&I)) { + auto *Var = DbgDeclare->getVariable(); + I.setOperand(1, MetadataAsValue::get(Ctx, reparentVar(Var))); + } +} + + #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void DebugLoc::dump() const { if (!Loc) diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 65e12456249..3b68d636587 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -267,6 +267,9 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport { /// \brief Keep track of the metadata nodes that have been checked already. SmallPtrSet<const Metadata *, 32> MDNodes; + /// Keep track which DISubprogram is attached to which function. + DenseMap<const DISubprogram *, const Function *> DISubprogramAttachments; + /// Track all DICompileUnits visited. SmallPtrSet<const Metadata *, 2> CUVisited; @@ -386,7 +389,7 @@ public: verifyCompileUnits(); verifyDeoptimizeCallingConvs(); - + DISubprogramAttachments.clear(); return !Broken; } @@ -2085,13 +2088,19 @@ void Verifier::visitFunction(const Function &F) { switch (I.first) { default: break; - case LLVMContext::MD_dbg: + case LLVMContext::MD_dbg: { ++NumDebugAttachments; AssertDI(NumDebugAttachments == 1, "function must have a single !dbg attachment", &F, I.second); AssertDI(isa<DISubprogram>(I.second), "function !dbg attachment must be a subprogram", &F, I.second); + auto *SP = cast<DISubprogram>(I.second); + const Function *&AttachedTo = DISubprogramAttachments[SP]; + AssertDI(!AttachedTo || AttachedTo == &F, + "DISubprogram attached to more than one function", SP, &F); + AttachedTo = &F; break; + } case LLVMContext::MD_prof: ++NumProfAttachments; Assert(NumProfAttachments == 1, |

