diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -64,57 +64,45 @@ return Declares; } -void llvm::findDbgValues(SmallVectorImpl &DbgValues, Value *V) { +template +static void findDbgIntrinsics(SmallVectorImpl &Result, Value *V) { // This function is hot. Check whether the value has any metadata to avoid a // DenseMap lookup. if (!V->isUsedByMetadata()) return; + + LLVMContext &Ctx = V->getContext(); // TODO: If this value appears multiple times in a DIArgList, we should still // only add the owning DbgValueInst once; use this set to track ArgListUsers. // This behaviour can be removed when we can automatically remove duplicates. - SmallPtrSet EncounteredDbgValues; - if (auto *L = LocalAsMetadata::getIfExists(V)) { - if (auto *MDV = MetadataAsValue::getIfExists(V->getContext(), L)) { + // V will also appear twice in a dbg.assign if its used in the both the value + // and address components. + SmallPtrSet EncounteredIntrinsics; + + /// Append IntrinsicT users of MetadataAsValue(MD). + auto AppendUsers = [&Ctx, &EncounteredIntrinsics, &Result](Metadata *MD) { + if (auto *MDV = MetadataAsValue::getIfExists(Ctx, MD)) { for (User *U : MDV->users()) - if (DbgValueInst *DVI = dyn_cast(U)) - DbgValues.push_back(DVI); - } - for (Metadata *AL : L->getAllArgListUsers()) { - if (auto *MDV = MetadataAsValue::getIfExists(V->getContext(), AL)) { - for (User *U : MDV->users()) - if (DbgValueInst *DVI = dyn_cast(U)) - if (EncounteredDbgValues.insert(DVI).second) - DbgValues.push_back(DVI); - } + if (IntrinsicT *DVI = dyn_cast(U)) + if (EncounteredIntrinsics.insert(DVI).second) + Result.push_back(DVI); } + }; + + if (auto *L = LocalAsMetadata::getIfExists(V)) { + AppendUsers(L); + for (Metadata *AL : L->getAllArgListUsers()) + AppendUsers(AL); } } +void llvm::findDbgValues(SmallVectorImpl &DbgValues, Value *V) { + findDbgIntrinsics(DbgValues, V); +} + void llvm::findDbgUsers(SmallVectorImpl &DbgUsers, Value *V) { - // This function is hot. Check whether the value has any metadata to avoid a - // DenseMap lookup. - if (!V->isUsedByMetadata()) - return; - // TODO: If this value appears multiple times in a DIArgList, we should still - // only add the owning DbgValueInst once; use this set to track ArgListUsers. - // This behaviour can be removed when we can automatically remove duplicates. - SmallPtrSet EncounteredDbgValues; - if (auto *L = LocalAsMetadata::getIfExists(V)) { - if (auto *MDV = MetadataAsValue::getIfExists(V->getContext(), L)) { - for (User *U : MDV->users()) - if (DbgVariableIntrinsic *DII = dyn_cast(U)) - DbgUsers.push_back(DII); - } - for (Metadata *AL : L->getAllArgListUsers()) { - if (auto *MDV = MetadataAsValue::getIfExists(V->getContext(), AL)) { - for (User *U : MDV->users()) - if (DbgVariableIntrinsic *DII = dyn_cast(U)) - if (EncounteredDbgValues.insert(DII).second) - DbgUsers.push_back(DII); - } - } - } + findDbgIntrinsics(DbgUsers, V); } DISubprogram *llvm::getDISubprogram(const MDNode *Scope) { diff --git a/llvm/unittests/Transforms/Utils/LocalTest.cpp b/llvm/unittests/Transforms/Utils/LocalTest.cpp --- a/llvm/unittests/Transforms/Utils/LocalTest.cpp +++ b/llvm/unittests/Transforms/Utils/LocalTest.cpp @@ -651,6 +651,60 @@ EXPECT_EQ(DLA, DLB); } +TEST(Local, FindDbgUsers) { + LLVMContext Ctx; + std::unique_ptr M = parseIR(Ctx, + R"( + define dso_local void @fun(ptr %a) #0 !dbg !11 { + entry: + call void @llvm.dbg.assign(metadata ptr %a, metadata !16, metadata !DIExpression(), metadata !15, metadata ptr %a, metadata !DIExpression()), !dbg !19 + ret void + } + + declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2, !3, !9} + !llvm.ident = !{!10} + + !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 17.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) + !1 = !DIFile(filename: "test.cpp", directory: "/") + !2 = !{i32 7, !"Dwarf Version", i32 5} + !3 = !{i32 2, !"Debug Info Version", i32 3} + !4 = !{i32 1, !"wchar_size", i32 4} + !9 = !{i32 7, !"debug-info-assignment-tracking", i1 true} + !10 = !{!"clang version 17.0.0"} + !11 = distinct !DISubprogram(name: "fun", linkageName: "fun", scope: !1, file: !1, line: 1, type: !12, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14) + !12 = !DISubroutineType(types: !13) + !13 = !{null} + !14 = !{} + !15 = distinct !DIAssignID() + !16 = !DILocalVariable(name: "x", scope: !11, file: !1, line: 2, type: !17) + !17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64) + !18 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !19 = !DILocation(line: 0, scope: !11) + )"); + + bool BrokenDebugInfo = true; + verifyModule(*M, &errs(), &BrokenDebugInfo); + ASSERT_FALSE(BrokenDebugInfo); + + Function &Fun = *cast(M->getNamedValue("fun")); + Value *Arg = Fun.getArg(0); + + SmallVector Users; + // Arg (%a) is used twice by a single dbg.assign. Check findDbgUsers returns + // only 1 pointer to it rather than 2. + findDbgUsers(Users, Arg); + EXPECT_EQ(Users.size(), 1u); + + SmallVector Vals; + // Arg (%a) is used twice by a single dbg.assign. Check findDbgValues returns + // only 1 pointer to it rather than 2. + findDbgValues(Vals, Arg); + EXPECT_EQ(Vals.size(), 1u); +} + TEST(Local, ReplaceAllDbgUsesWith) { using namespace llvm::dwarf;