Index: llvm/lib/IR/DebugInfo.cpp =================================================================== --- llvm/lib/IR/DebugInfo.cpp +++ llvm/lib/IR/DebugInfo.cpp @@ -72,12 +72,15 @@ // 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. + // V will also appear twice in a dbg.assign if its used in the both the value + // and address components. SmallPtrSet EncounteredDbgValues; if (auto *L = LocalAsMetadata::getIfExists(V)) { if (auto *MDV = MetadataAsValue::getIfExists(V->getContext(), L)) { for (User *U : MDV->users()) if (DbgValueInst *DVI = dyn_cast(U)) - DbgValues.push_back(DVI); + if (EncounteredDbgValues.insert(DVI).second) + DbgValues.push_back(DVI); } for (Metadata *AL : L->getAllArgListUsers()) { if (auto *MDV = MetadataAsValue::getIfExists(V->getContext(), AL)) { @@ -99,12 +102,15 @@ // 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. + // V will also appear twice in a dbg.assign if its used in the both the value + // and address components 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); + if (EncounteredDbgValues.insert(DII).second) + DbgUsers.push_back(DII); } for (Metadata *AL : L->getAllArgListUsers()) { if (auto *MDV = MetadataAsValue::getIfExists(V->getContext(), AL)) { Index: llvm/unittests/Transforms/Utils/LocalTest.cpp =================================================================== --- llvm/unittests/Transforms/Utils/LocalTest.cpp +++ 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(), 1); + + 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(), 1); +} + TEST(Local, ReplaceAllDbgUsesWith) { using namespace llvm::dwarf;