diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -3564,6 +3564,15 @@ // here, but that computation has been sunk. SmallVector DbgUsers; findDbgUsers(DbgUsers, I); + // Process the DbgUsers in reverse order, as we only want to clone the last + // appearing debug intrinsic for each given variable. + llvm::sort(DbgUsers, [](auto *A, auto *B) { + if (A->getParent() == B->getParent()) + return B->comesBefore(A); + // We only care about sorting DbgUsers in the same BB, cross-block ordering + // does not matter here. + return A->getParent() > B->getParent(); + }); // Update the arguments of a dbg.declare instruction, so that it // does not point into a sunk instruction. @@ -3579,6 +3588,7 @@ }; SmallVector DIIClones; + SmallSet SunkVariables; for (auto User : DbgUsers) { // A dbg.declare instruction should not be cloned, since there can only be // one per variable fragment. It should be left in the original place @@ -3587,6 +3597,13 @@ if (User->getParent() != SrcBlock || updateDbgDeclare(User)) continue; + DebugVariable DbgUserVariable = + DebugVariable(User->getVariable(), User->getExpression(), + User->getDebugLoc()->getInlinedAt()); + + if (!SunkVariables.insert(DbgUserVariable).second) + continue; + DIIClones.emplace_back(cast(User->clone())); LLVM_DEBUG(dbgs() << "CLONE: " << *DIIClones.back() << '\n'); } @@ -3594,7 +3611,9 @@ // Perform salvaging without the clones, then sink the clones. if (!DIIClones.empty()) { salvageDebugInfoForDbgValues(*I, DbgUsers); - for (auto &DIIClone : DIIClones) { + // The clones are in reverse order of original appearance, reverse again to + // maintain the original order. + for (auto &DIIClone : llvm::reverse(DIIClones)) { DIIClone->insertBefore(&*InsertPos); LLVM_DEBUG(dbgs() << "SINK: " << *DIIClone << '\n'); } diff --git a/llvm/test/Transforms/InstCombine/debuginfo-sink.ll b/llvm/test/Transforms/InstCombine/debuginfo-sink.ll --- a/llvm/test/Transforms/InstCombine/debuginfo-sink.ll +++ b/llvm/test/Transforms/InstCombine/debuginfo-sink.ll @@ -52,6 +52,33 @@ ret i32 %0 } +; This GEP is sunk, and has multiple debug uses in the same block. Check that +; only the last use is cloned into the sunk block, and that both of the +; original dbg.values are salvaged. +; +; CHECK-LABEL: define i32 @baz(i32* +; CHECK: call void @llvm.dbg.value(metadata i32* %a, metadata !{{[0-9]+}}, +; CHECK-SAME: metadata !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value)) +; CHECK-NEXT: call void @llvm.dbg.value(metadata i32* %a, metadata !{{[0-9]+}}, +; CHECK-SAME: metadata !DIExpression(DW_OP_plus_uconst, 4, DW_OP_plus_uconst, 5, DW_OP_stack_value)) +; CHECK-NEXT: br label %sink1 + +define i32 @baz(i32 *%a) !dbg !80 { +entry: + %gep = getelementptr i32, i32 *%a, i32 1 + call void @llvm.dbg.value(metadata i32 *%gep, metadata !83, metadata !12), !dbg !84 + call void @llvm.dbg.value(metadata i32 *%gep, metadata !83, metadata !DIExpression(DW_OP_plus_uconst, 5)), !dbg !85 + br label %sink1 + +sink1: +; CHECK-LABEL: sink1: +; CHECK: call void @llvm.dbg.value(metadata i32* %gep, +; CHECK-SAME: metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_plus_uconst, 5)) +; CHECK-NEXT: load + %0 = load i32, i32* %gep, align 4, !dbg !85 + ret i32 %0, !dbg !85 +} + !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5} !llvm.ident = !{!6} @@ -76,3 +103,7 @@ !72 = !{!10, !10, !10} !73 = !DILocalVariable(name: "k", scope: !70, file: !1, line: 2, type: !10) !74 = !DILocation(line: 5, column: 3, scope: !70) +!80 = distinct !DISubprogram(name: "baz", scope: !1, file: !1, line: 2, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2) +!83 = !DILocalVariable(name: "l", scope: !80, file: !1, line: 2, type: !10) +!84 = !DILocation(line: 5, column: 3, scope: !80) +!85 = !DILocation(line: 6, column: 3, scope: !80) diff --git a/llvm/test/Transforms/InstCombine/debuginfo_add.ll b/llvm/test/Transforms/InstCombine/debuginfo_add.ll --- a/llvm/test/Transforms/InstCombine/debuginfo_add.ll +++ b/llvm/test/Transforms/InstCombine/debuginfo_add.ll @@ -36,8 +36,8 @@ ; The add is later eliminated, so we verify that the dbg.value is salvaged by using DW_OP_minus. ; CHECK-LABEL: for.body.lr.ph: ; CHECK-NEXT: %0 = load - ; CHECK-NEXT: call void @llvm.dbg.value(metadata i64 %0, metadata !26, metadata !DIExpression(DW_OP_constu, 4096, DW_OP_minus, DW_OP_stack_value)), !dbg ! ; CHECK-NEXT: call void @llvm.dbg.value(metadata i64 %0, metadata !25, metadata !DIExpression()), !dbg ! + ; CHECK-NEXT: call void @llvm.dbg.value(metadata i64 %0, metadata !26, metadata !DIExpression(DW_OP_constu, 4096, DW_OP_minus, DW_OP_stack_value)), !dbg ! br label %for.body, !dbg !32 for.body: ; preds = %for.body.lr.ph, %for.body