diff --git a/llvm/include/llvm/IR/DebugInfo.h b/llvm/include/llvm/IR/DebugInfo.h index 92beebed8ad51..5d6e8c2fd28da 100644 --- a/llvm/include/llvm/IR/DebugInfo.h +++ b/llvm/include/llvm/IR/DebugInfo.h @@ -34,6 +34,7 @@ namespace llvm { class DbgDeclareInst; class DbgValueInst; class DbgVariableIntrinsic; +class DPValue; class Instruction; class Module; @@ -42,10 +43,12 @@ class Module; TinyPtrVector FindDbgDeclareUses(Value *V); /// Finds the llvm.dbg.value intrinsics describing a value. -void findDbgValues(SmallVectorImpl &DbgValues, Value *V); +void findDbgValues(SmallVectorImpl &DbgValues, + Value *V, SmallVectorImpl *DPValues = nullptr); /// Finds the debug info intrinsics describing a value. -void findDbgUsers(SmallVectorImpl &DbgInsts, Value *V); +void findDbgUsers(SmallVectorImpl &DbgInsts, + Value *V, SmallVectorImpl *DPValues = nullptr); /// Find subprogram that is enclosing this scope. DISubprogram *getDISubprogram(const MDNode *Scope); diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp index b0a79ad897fa9..600643704522f 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -25,6 +25,7 @@ #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" +#include "llvm/IR/DebugProgramInstruction.h" #include "llvm/IR/Function.h" #include "llvm/IR/GVMaterializer.h" #include "llvm/IR/Instruction.h" @@ -65,7 +66,8 @@ TinyPtrVector llvm::FindDbgDeclareUses(Value *V) { } template -static void findDbgIntrinsics(SmallVectorImpl &Result, Value *V) { +static void findDbgIntrinsics(SmallVectorImpl &Result, + Value *V, SmallVectorImpl *DPValues) { // This function is hot. Check whether the value has any metadata to avoid a // DenseMap lookup. if (!V->isUsedByMetadata()) @@ -78,31 +80,51 @@ static void findDbgIntrinsics(SmallVectorImpl &Result, Value *V) { // V will also appear twice in a dbg.assign if its used in the both the value // and address components. SmallPtrSet EncounteredIntrinsics; + SmallPtrSet EncounteredDPValues; /// Append IntrinsicT users of MetadataAsValue(MD). - auto AppendUsers = [&Ctx, &EncounteredIntrinsics, &Result](Metadata *MD) { + auto AppendUsers = [&Ctx, &EncounteredIntrinsics, &Result, + DPValues](Metadata *MD) { if (auto *MDV = MetadataAsValue::getIfExists(Ctx, MD)) { for (User *U : MDV->users()) if (IntrinsicT *DVI = dyn_cast(U)) if (EncounteredIntrinsics.insert(DVI).second) Result.push_back(DVI); } + if (!DPValues) + return; + // Get DPValues that use this as a single value. + if (LocalAsMetadata *L = dyn_cast(MD)) { + for (DPValue *DPV : L->getAllDPValueUsers()) { + if (DPV->getType() == DPValue::LocationType::Value) + DPValues->push_back(DPV); + } + } }; if (auto *L = LocalAsMetadata::getIfExists(V)) { AppendUsers(L); - for (Metadata *AL : L->getAllArgListUsers()) + for (Metadata *AL : L->getAllArgListUsers()) { AppendUsers(AL); + if (!DPValues) + continue; + DIArgList *DI = cast(AL); + for (DPValue *DPV : DI->getAllDPValueUsers()) + if (DPV->getType() == DPValue::LocationType::Value) + if (EncounteredDPValues.insert(DPV).second) + DPValues->push_back(DPV); + } } } -void llvm::findDbgValues(SmallVectorImpl &DbgValues, Value *V) { - findDbgIntrinsics(DbgValues, V); +void llvm::findDbgValues(SmallVectorImpl &DbgValues, + Value *V, SmallVectorImpl *DPValues) { + findDbgIntrinsics(DbgValues, V, DPValues); } void llvm::findDbgUsers(SmallVectorImpl &DbgUsers, - Value *V) { - findDbgIntrinsics(DbgUsers, V); + Value *V, SmallVectorImpl *DPValues) { + findDbgIntrinsics(DbgUsers, V, DPValues); } DISubprogram *llvm::getDISubprogram(const MDNode *Scope) { diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp index b485a6275b4de..c05f9ac5a0fe0 100644 --- a/llvm/lib/IR/Value.cpp +++ b/llvm/lib/IR/Value.cpp @@ -574,11 +574,17 @@ void Value::replaceUsesWithIf(Value *New, /// with New. static void replaceDbgUsesOutsideBlock(Value *V, Value *New, BasicBlock *BB) { SmallVector DbgUsers; - findDbgUsers(DbgUsers, V); + SmallVector DPUsers; + findDbgUsers(DbgUsers, V, &DPUsers); for (auto *DVI : DbgUsers) { if (DVI->getParent() != BB) DVI->replaceVariableLocationOp(V, New); } + for (auto *DPV : DPUsers) { + DPMarker *Marker = DPV->getMarker(); + if (Marker->getParent() != BB) + DPV->replaceVariableLocationOp(V, New); + } } // Like replaceAllUsesWith except it does not handle constants or basic blocks. diff --git a/llvm/unittests/IR/DebugInfoTest.cpp b/llvm/unittests/IR/DebugInfoTest.cpp index 034a9230bbadb..a408c0af5623b 100644 --- a/llvm/unittests/IR/DebugInfoTest.cpp +++ b/llvm/unittests/IR/DebugInfoTest.cpp @@ -234,6 +234,56 @@ TEST(DbgVariableIntrinsic, EmptyMDIsKillLocation) { EXPECT_TRUE(DbgDeclare->isKillLocation()); } +// Duplicate of above test, but in DPValue representation. +TEST(MetadataTest, DeleteInstUsedByDPValue) { + LLVMContext C; + std::unique_ptr M = parseIR(C, R"( + define i16 @f(i16 %a) !dbg !6 { + %b = add i16 %a, 1, !dbg !11 + call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11 + call void @llvm.dbg.value(metadata !DIArgList(i16 %a, i16 %b), metadata !9, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus)), !dbg !11 + ret i16 0, !dbg !11 + } + declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + attributes #0 = { nounwind readnone speculatable willreturn } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!5} + + !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "t.ll", directory: "/") + !2 = !{} + !5 = !{i32 2, !"Debug Info Version", i32 3} + !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) + !7 = !DISubroutineType(types: !2) + !8 = !{!9} + !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) + !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned) + !11 = !DILocation(line: 1, column: 1, scope: !6) +)"); + + bool OldDbgValueMode = UseNewDbgInfoFormat; + UseNewDbgInfoFormat = true; + Instruction &I = *M->getFunction("f")->getEntryBlock().getFirstNonPHI(); + M->convertToNewDbgValues(); + + // Find the DPValues using %b. + SmallVector DVIs; + SmallVector DPVs; + findDbgValues(DVIs, &I, &DPVs); + ASSERT_EQ(DPVs.size(), 2u); + + // Delete %b. The DPValue should now point to undef. + I.eraseFromParent(); + EXPECT_EQ(DPVs[0]->getNumVariableLocationOps(), 1u); + EXPECT_TRUE(isa(DPVs[0]->getVariableLocationOp(0))); + EXPECT_TRUE(DPVs[0]->isKillLocation()); + EXPECT_EQ(DPVs[1]->getNumVariableLocationOps(), 2u); + EXPECT_TRUE(isa(DPVs[1]->getVariableLocationOp(1))); + EXPECT_TRUE(DPVs[1]->isKillLocation()); + UseNewDbgInfoFormat = OldDbgValueMode; +} + TEST(DIBuiler, CreateFile) { LLVMContext Ctx; std::unique_ptr M(new Module("MyModule", Ctx)); diff --git a/llvm/unittests/IR/ValueTest.cpp b/llvm/unittests/IR/ValueTest.cpp index 76a0b0c04f5f2..760b6b603c6a5 100644 --- a/llvm/unittests/IR/ValueTest.cpp +++ b/llvm/unittests/IR/ValueTest.cpp @@ -17,6 +17,8 @@ #include "gtest/gtest.h" using namespace llvm; +extern cl::opt UseNewDbgInfoFormat; + namespace { TEST(ValueTest, UsedInBasicBlock) { @@ -314,4 +316,78 @@ TEST(ValueTest, replaceUsesOutsideBlock) { ASSERT_TRUE(ExitDbg->getValue(0) == cast(B)); ASSERT_TRUE(Ret->getOperand(0) == cast(B)); } + +TEST(ValueTest, replaceUsesOutsideBlockDPValue) { + // Check that Value::replaceUsesOutsideBlock(New, BB) replaces uses outside + // BB, including DPValues. + const auto *IR = R"( + define i32 @f() !dbg !6 { + entry: + %a = add i32 0, 1, !dbg !15 + %b = add i32 0, 2, !dbg !15 + %c = add i32 %a, 2, !dbg !15 + call void @llvm.dbg.value(metadata i32 %a, metadata !9, metadata !DIExpression()), !dbg !15 + br label %exit, !dbg !15 + + exit: + call void @llvm.dbg.value(metadata i32 %a, metadata !11, metadata !DIExpression()), !dbg !16 + ret i32 %a, !dbg !16 + } + + declare void @llvm.dbg.value(metadata, metadata, metadata) + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!5} + + !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "test.ll", directory: "/") + !2 = !{} + !5 = !{i32 2, !"Debug Info Version", i32 3} + !6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !8) + !7 = !DISubroutineType(types: !2) + !8 = !{!9, !11} + !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) + !10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_signed) + !11 = !DILocalVariable(name: "2", scope: !6, file: !1, line: 2, type: !12) + !12 = !DIBasicType(name: "ty64", size: 64, encoding: DW_ATE_signed) + !15 = !DILocation(line: 1, column: 1, scope: !6) + !16 = !DILocation(line: 5, column: 1, scope: !6) + )"; + LLVMContext Ctx; + SMDiagnostic Err; + std::unique_ptr M = parseAssemblyString(IR, Err, Ctx); + if (!M) + Err.print("ValueTest", errs()); + + bool OldDbgValueMode = UseNewDbgInfoFormat; + UseNewDbgInfoFormat = true; + M->convertToNewDbgValues(); + + auto GetNext = [](auto *I) { return &*++I->getIterator(); }; + + Function *F = M->getFunction("f"); + // Entry. + BasicBlock *Entry = &F->front(); + Instruction *A = &Entry->front(); + Instruction *B = GetNext(A); + Instruction *C = GetNext(B); + Instruction *Branch = GetNext(C); + // Exit. + BasicBlock *Exit = GetNext(Entry); + Instruction *Ret = &Exit->front(); + + EXPECT_TRUE(Branch->hasDbgValues()); + EXPECT_TRUE(Ret->hasDbgValues()); + + DPValue *DPV1 = &*Branch->getDbgValueRange().begin(); + DPValue *DPV2 = &*Ret->getDbgValueRange().begin(); + + A->replaceUsesOutsideBlock(B, Entry); + // These users are in Entry so shouldn't be changed. + EXPECT_TRUE(DPV1->getVariableLocationOp(0) == cast(A)); + // These users are outside Entry so should be changed. + EXPECT_TRUE(DPV2->getVariableLocationOp(0) == cast(B)); + UseNewDbgInfoFormat = OldDbgValueMode; +} + } // end anonymous namespace