Index: include/llvm/IR/DebugLoc.h =================================================================== --- include/llvm/IR/DebugLoc.h +++ include/llvm/IR/DebugLoc.h @@ -80,6 +80,22 @@ static DebugLoc get(unsigned Line, unsigned Col, const MDNode *Scope, const MDNode *InlinedAt = nullptr); + enum { ReplaceLastInlinedAt = true }; + /// Rebuild the entire inlined-at chain for this instruction so that the top of + /// the chain now is inlined-at the new call site. + /// \param InlinedAt The new outermost inlined-at in the chain. + /// \param ReplaceLast Replace the last location in the inlined-at chain. + static DebugLoc appendInlinedAt(DebugLoc DL, DILocation *InlinedAt, + LLVMContext &Ctx, + DenseMap &Cache, + bool ReplaceLast = false); + + /// Reparent all debug locations referenced by \c I that belong to \c OrigSP + /// to become (possibly indirect) children of \c NewSP. + static void reparentDebugInfo(Instruction &I, DISubprogram *OrigSP, + DISubprogram *NewSP, + DenseMap &Cache); + unsigned getLine() const; unsigned getCol() const; MDNode *getScope() const; Index: lib/IR/DebugLoc.cpp =================================================================== --- lib/IR/DebugLoc.cpp +++ 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,121 @@ const_cast(InlinedAt)); } +DebugLoc DebugLoc::appendInlinedAt(DebugLoc DL, DILocation *InlinedAt, + LLVMContext &Ctx, + DenseMap &Cache, + bool ReplaceLast) { + SmallVector 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(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 &Cache) { + SmallVector ScopeChain; + DIScope *Last = NewSP; + DIScope *CurScope = Scope; + do { + if (auto *SP = dyn_cast(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(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(MD)) + Cache[MD] = Last = DILexicalBlock::getDistinct( + Ctx, Last, LB->getFile(), LB->getLine(), LB->getColumn()); + else if (auto *LB = dyn_cast(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 &Cache) { + auto DL = I.getDebugLoc(); + if (!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; + assert(InlinedAt->getScope() == OrigSP && + "inlined-at pointing to another function"); + 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) -> DILocalVariable * { + return DILocalVariable::getDistinct( + Ctx, + cast( + 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(&I)) { + auto *Var = DbgValue->getVariable(); + I.setOperand(2, MetadataAsValue::get(Ctx, reparentVar(Var))); + } else if (auto *DbgDeclare = dyn_cast(&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) Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -267,6 +267,9 @@ /// \brief Keep track of the metadata nodes that have been checked already. SmallPtrSet MDNodes; + /// Keep track which DISubprogram is attached to which function. + DenseMap DISubprogramAttachments; + /// Track all DICompileUnits visited. SmallPtrSet CUVisited; @@ -386,7 +389,7 @@ verifyCompileUnits(); verifyDeoptimizeCallingConvs(); - + DISubprogramAttachments.clear(); return !Broken; } @@ -2085,13 +2088,19 @@ 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(I.second), "function !dbg attachment must be a subprogram", &F, I.second); + auto *SP = cast(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, Index: lib/Transforms/Utils/CloneFunction.cpp =================================================================== --- lib/Transforms/Utils/CloneFunction.cpp +++ lib/Transforms/Utils/CloneFunction.cpp @@ -41,6 +41,7 @@ ValueToValueMapTy &VMap, const Twine &NameSuffix, Function *F, ClonedCodeInfo *CodeInfo) { + DenseMap Cache; BasicBlock *NewBB = BasicBlock::Create(BB->getContext(), "", F); if (BB->hasName()) NewBB->setName(BB->getName()+NameSuffix); @@ -50,6 +51,9 @@ for (BasicBlock::const_iterator II = BB->begin(), IE = BB->end(); II != IE; ++II) { Instruction *NewInst = II->clone(); + if (F && F->getSubprogram()) + DebugLoc::reparentDebugInfo(*NewInst, BB->getParent()->getSubprogram(), + F->getSubprogram(), Cache); if (II->hasName()) NewInst->setName(II->getName()+NameSuffix); NewBB->getInstList().push_back(NewInst); @@ -120,12 +124,28 @@ SmallVector, 1> MDs; OldFunc->getAllMetadata(MDs); - for (auto MD : MDs) - NewFunc->addMetadata( - MD.first, - *MapMetadata(MD.second, VMap, - ModuleLevelChanges ? RF_None : RF_NoModuleLevelChanges, - TypeMapper, Materializer)); + for (auto MD : MDs) { + MDNode *NewMD; + bool MustCloneSP = + (MD.first == LLVMContext::MD_dbg && OldFunc->getParent() && + OldFunc->getParent() == NewFunc->getParent()); + if (MustCloneSP) { + auto *SP = cast(MD.second); + NewMD = DISubprogram::getDistinct( + NewFunc->getContext(), SP->getScope(), SP->getName(), + NewFunc->getName(), SP->getFile(), SP->getLine(), SP->getType(), + SP->isLocalToUnit(), SP->isDefinition(), SP->getScopeLine(), + SP->getContainingType(), SP->getVirtuality(), SP->getVirtualIndex(), + SP->getThisAdjustment(), SP->getFlags(), SP->isOptimized(), + SP->getUnit(), SP->getTemplateParams(), SP->getDeclaration(), + SP->getVariables(), SP->getThrownTypes()); + } else + NewMD = + MapMetadata(MD.second, VMap, + ModuleLevelChanges ? RF_None : RF_NoModuleLevelChanges, + TypeMapper, Materializer); + NewFunc->addMetadata(MD.first, *NewMD); + } // Loop over all of the basic blocks in the function, cloning them as // appropriate. Note that we save BE this way in order to handle cloning of @@ -148,8 +168,8 @@ // implementation, which generates an invalid blockaddress when // cloning a function.) if (BB.hasAddressTaken()) { - Constant *OldBBAddr = BlockAddress::get(const_cast(OldFunc), - const_cast(&BB)); + Constant *OldBBAddr = BlockAddress::get(const_cast(OldFunc), + const_cast(&BB)); VMap[OldBBAddr] = BlockAddress::get(NewFunc, CBB); } Index: lib/Transforms/Utils/InlineFunction.cpp =================================================================== --- lib/Transforms/Utils/InlineFunction.cpp +++ lib/Transforms/Utils/InlineFunction.cpp @@ -1302,41 +1302,6 @@ return false; } -/// Rebuild the entire inlined-at chain for this instruction so that the top of -/// the chain now is inlined-at the new call site. -static DebugLoc -updateInlinedAtInfo(const DebugLoc &DL, DILocation *InlinedAtNode, - LLVMContext &Ctx, - DenseMap &IANodes) { - SmallVector InlinedAtLocations; - DILocation *Last = InlinedAtNode; - DILocation *CurInlinedAt = DL; - - // Gather all the inlined-at nodes - while (DILocation *IA = CurInlinedAt->getInlinedAt()) { - // Skip any we've already built nodes for - if (DILocation *Found = IANodes[IA]) { - Last = 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)) { - Last = IANodes[MD] = DILocation::getDistinct( - Ctx, MD->getLine(), MD->getColumn(), MD->getScope(), Last); - } - - // And finally create the normal location for this instruction, referring to - // the new inlined-at chain. - return DebugLoc::get(DL.getLine(), DL.getCol(), DL.getScope(), Last); -} - /// Return the result of AI->isStaticAlloca() if AI were moved to the entry /// block. Allocas used in inalloca calls and allocas of dynamic array size /// cannot be static. @@ -1364,14 +1329,14 @@ // Cache the inlined-at nodes as they're built so they are reused, without // this every instruction's inlined-at chain would become distinct from each // other. - DenseMap IANodes; + DenseMap IANodes; for (; FI != Fn->end(); ++FI) { for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) { if (DebugLoc DL = BI->getDebugLoc()) { - BI->setDebugLoc( - updateInlinedAtInfo(DL, InlinedAtNode, BI->getContext(), IANodes)); + BI->setDebugLoc(DebugLoc::appendInlinedAt(DL, InlinedAtNode, + BI->getContext(), IANodes)); continue; } Index: test/Verifier/metadata-function-dbg.ll =================================================================== --- test/Verifier/metadata-function-dbg.ll +++ test/Verifier/metadata-function-dbg.ll @@ -3,12 +3,18 @@ ; CHECK: function declaration may not have a !dbg attachment declare !dbg !4 void @f1() -define void @f2() !dbg !4 { +; CHECK: function must have a single !dbg attachment +define void @f2() !dbg !4 !dbg !4 { unreachable } -; CHECK: function must have a single !dbg attachment -define void @f3() !dbg !4 !dbg !4 { +; CHECK: DISubprogram attached to more than one function +define void @f3() !dbg !4 { + unreachable +} + +; CHECK: DISubprogram attached to more than one function +define void @f4() !dbg !4 { unreachable } @@ -16,7 +22,7 @@ ; CHECK: function !dbg attachment must be a subprogram ; CHECK-NEXT: void ()* @bar ; CHECK-NEXT: !{{[0-9]+}} = !{} -define void @bar() !dbg !6 { +define void @bar() !dbg !3 { unreachable } @@ -26,5 +32,5 @@ !llvm.dbg.cu = !{!1} !1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2) !2 = !DIFile(filename: "t.c", directory: "/path/to/dir") +!3 = !{} !4 = distinct !DISubprogram(name: "foo", scope: !1, file: !2, unit: !1) -!6 = !{} Index: unittests/Transforms/Utils/Cloning.cpp =================================================================== --- unittests/Transforms/Utils/Cloning.cpp +++ unittests/Transforms/Utils/Cloning.cpp @@ -296,7 +296,6 @@ Value* AllocaContent = IBuilder.getInt32(1); Instruction* Store = IBuilder.CreateStore(AllocaContent, Alloca); IBuilder.SetCurrentDebugLocation(DebugLoc::get(5, 2, Subprogram)); - Instruction* Terminator = IBuilder.CreateRetVoid(); // Create a local variable around the alloca auto *IntType = DBuilder.createBasicType("int", 32, dwarf::DW_ATE_signed); @@ -306,12 +305,25 @@ auto *DL = DILocation::get(Subprogram->getContext(), 5, 0, Subprogram); DBuilder.insertDeclare(Alloca, Variable, E, DL, Store); DBuilder.insertDbgValueIntrinsic(AllocaContent, 0, Variable, E, DL, - Terminator); - // Finalize the debug info + Entry); + // Also create an inlined variable. + auto *InlinedSP = + DBuilder.createFunction(CU, "inlined", "inlined", File, 8, FuncType, + true, true, 9, DINode::FlagZero, false); + auto *InlinedVar = + DBuilder.createAutoVariable(InlinedSP, "inlined", File, 5, IntType, true); + auto *Scope = DBuilder.createLexicalBlock( + DBuilder.createLexicalBlockFile(InlinedSP, File), File, 1, 1); + auto InlinedDL = + DebugLoc::get(9, 4, Scope, DebugLoc::get(5, 2, Subprogram)); + IBuilder.SetCurrentDebugLocation(InlinedDL); + DBuilder.insertDeclare(Alloca, InlinedVar, E, InlinedDL, Store); + IBuilder.CreateStore(IBuilder.getInt32(2), Alloca); + // Finalize the debug info. DBuilder.finalize(); + IBuilder.CreateRetVoid(); - - // Create another, empty, compile unit + // Create another, empty, compile unit. DIBuilder DBuilder2(*M); DBuilder2.createCompileUnit(dwarf::DW_LANG_C99, DBuilder.createFile("extra.c", "/file/dir"), @@ -347,13 +359,9 @@ EXPECT_FALSE(verifyModule(*M)); unsigned SubprogramCount = Finder->subprogram_count(); - EXPECT_EQ(1U, SubprogramCount); - - auto Iter = Finder->subprograms().begin(); - auto *Sub = cast(*Iter); + EXPECT_EQ(3U, SubprogramCount); - EXPECT_TRUE(Sub == OldFunc->getSubprogram()); - EXPECT_TRUE(Sub == NewFunc->getSubprogram()); + EXPECT_FALSE(NewFunc->getSubprogram() == OldFunc->getSubprogram()); } // Test that instructions in the old function still belong to it in the @@ -380,8 +388,8 @@ EXPECT_EQ(OldDL.getCol(), NewDL.getCol()); // But that they belong to different functions - auto *OldSubprogram = cast(OldDL.getScope()); - auto *NewSubprogram = cast(NewDL.getScope()); + auto *OldSubprogram = cast(OldDL.getInlinedAtScope()); + auto *NewSubprogram = cast(NewDL.getInlinedAtScope()); EXPECT_EQ(OldFunc->getSubprogram(), OldSubprogram); EXPECT_EQ(NewFunc->getSubprogram(), NewSubprogram); } @@ -416,22 +424,26 @@ EXPECT_EQ(NewFunc, cast(NewIntrin->getAddress())-> getParent()->getParent()); - // Old variable must belong to the old function - EXPECT_EQ(OldFunc->getSubprogram(), - cast(OldIntrin->getVariable()->getScope())); - // New variable must belong to the New function - EXPECT_EQ(NewFunc->getSubprogram(), - cast(NewIntrin->getVariable()->getScope())); + if (!OldIntrin->getDebugLoc()->getInlinedAt()) { + // Old variable must belong to the old function. + EXPECT_EQ(OldFunc->getSubprogram(), + cast(OldIntrin->getVariable()->getScope())); + // New variable must belong to the new function. + EXPECT_EQ(NewFunc->getSubprogram(), + cast(NewIntrin->getVariable()->getScope())); + } } else if (DbgValueInst* OldIntrin = dyn_cast(&OldI)) { DbgValueInst* NewIntrin = dyn_cast(&NewI); EXPECT_TRUE(NewIntrin); - // Old variable must belong to the old function - EXPECT_EQ(OldFunc->getSubprogram(), - cast(OldIntrin->getVariable()->getScope())); - // New variable must belong to the New function - EXPECT_EQ(NewFunc->getSubprogram(), - cast(NewIntrin->getVariable()->getScope())); + if (!OldIntrin->getDebugLoc()->getInlinedAt()) { + // Old variable must belong to the old function. + EXPECT_EQ(OldFunc->getSubprogram(), + cast(OldIntrin->getVariable()->getScope())); + // New variable must belong to the new function. + EXPECT_EQ(NewFunc->getSubprogram(), + cast(NewIntrin->getVariable()->getScope())); + } } ++OldIter;