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,14 @@ // here, but that computation has been sunk. SmallVector DbgUsers; findDbgUsers(DbgUsers, I); + // Process the sinking DbgUsers in reverse order, as we only want to clone the + // last appearing debug intrinsic for each given variable. + SmallVector DbgUsersToSink; + for (DbgVariableIntrinsic *DVI : DbgUsers) + if (DVI->getParent() == SrcBlock) + DbgUsersToSink.push_back(DVI); + llvm::sort(DbgUsersToSink, + [](auto *A, auto *B) { return B->comesBefore(A); }); // Update the arguments of a dbg.declare instruction, so that it // does not point into a sunk instruction. @@ -3579,12 +3587,20 @@ }; SmallVector DIIClones; - for (auto User : DbgUsers) { + SmallSet SunkVariables; + for (auto User : DbgUsersToSink) { // 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 // because the sunk instruction is not an alloca (otherwise we could not be // here). - if (User->getParent() != SrcBlock || updateDbgDeclare(User)) + if (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())); @@ -3594,7 +3610,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