Index: include/llvm/Transforms/Utils/Local.h =================================================================== --- include/llvm/Transforms/Utils/Local.h +++ include/llvm/Transforms/Utils/Local.h @@ -342,6 +342,11 @@ /// Returns true if any debug users were updated. bool salvageDebugInfo(Instruction &I); +/// Implementation of salvageDebugInfo, applying only to instructions in +/// \p Insns, rather than all debug users of \p I. +bool salvageDebugInfoForDbgValues( + Instruction &I, SmallVectorImpl &Insns); + /// Point debug users of \p From to \p To or salvage them. Use this function /// only when replacing all uses of \p From with \p To, with a guarantee that /// \p From is going to be deleted. Index: lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- lib/Transforms/InstCombine/InstructionCombining.cpp +++ lib/Transforms/InstCombine/InstructionCombining.cpp @@ -3093,13 +3093,17 @@ ++NumSunkInst; // Also sink all related debug uses from the source basic block. Otherwise we - // get debug use before the def. - SmallVector DbgUsers; + // get debug use before the def. Attempt to salvage debug uses first, as we + // don't wish to un-necessarily re-order variables. + SmallVector DbgUsers; findDbgUsers(DbgUsers, I); for (auto *DII : DbgUsers) { if (DII->getParent() == SrcBlock) { - DII->moveBefore(&*InsertPos); - LLVM_DEBUG(dbgs() << "SINK: " << *DII << '\n'); + SmallVector TmpUser{DII}; + if (!salvageDebugInfoForDbgValues(*I, TmpUser)) { + DII->moveBefore(&*InsertPos); + LLVM_DEBUG(dbgs() << "SINK: " << *DII << '\n'); + } } } return true; Index: lib/Transforms/Utils/Local.cpp =================================================================== --- lib/Transforms/Utils/Local.cpp +++ lib/Transforms/Utils/Local.cpp @@ -1594,6 +1594,11 @@ if (DbgUsers.empty()) return false; + return salvageDebugInfoForDbgValues(I, DbgUsers); +} + +bool llvm::salvageDebugInfoForDbgValues( + Instruction &I, SmallVectorImpl &DbgUsers) { auto &M = *I.getModule(); auto &DL = M.getDataLayout(); auto &Ctx = I.getContext(); @@ -1643,10 +1648,13 @@ // arithmetic to compute the variable's *value* in the DIExpression, we // need to mark the expression with a DW_OP_stack_value. APInt Offset(BitWidth, 0); - if (GEP->accumulateConstantOffset(M.getDataLayout(), Offset)) + if (GEP->accumulateConstantOffset(M.getDataLayout(), Offset)) { for (auto *DII : DbgUsers) applyOffset(DII, Offset.getSExtValue()); - return true; + return true; + } else { + return false; + } } else if (auto *BI = dyn_cast(&I)) { // Rewrite binary operations with constant integer operands. auto *ConstInt = dyn_cast(I.getOperand(1)); Index: test/Transforms/InstCombine/debuginfo_add.ll =================================================================== --- test/Transforms/InstCombine/debuginfo_add.ll +++ test/Transforms/InstCombine/debuginfo_add.ll @@ -22,6 +22,20 @@ ; Function Attrs: nounwind ssp define void @f(%struct.vm_object* %object, i64* nocapture readonly %start) local_unnamed_addr #0 !dbg !11 { entry: + + ; The 'load' and the 'add' are sunken out of this basic block. However it's + ; undesirable for the dbg.values to move: they can and should be salvaged. + ; Check that the middle dbg.value below is salvaged back to operating only + ; on %start rather than the sunk insts. + ; + ; CHECK-LABEL: entry: + ; CHECK: call void @llvm.dbg.value(metadata i64* %start, metadata !22, metadata !DIExpression()), !dbg ! + ; CHECK-NEXT: call void @llvm.dbg.value(metadata i64* %start, metadata !25, metadata !DIExpression(DW_OP_deref)), !dbg ! + ; CHECK-NEXT: call void @llvm.dbg.value(metadata i64* %start, metadata !26, metadata !DIExpression(DW_OP_deref, DW_OP_constu, 4096, DW_OP_minus, DW_OP_stack_value)), !dbg ! + ; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 undef, metadata !23, metadata !DIExpression()), !dbg ! + ; CHECK-NEXT: br i1 undef + + tail call void @llvm.dbg.value(metadata %struct.vm_object* %object, metadata !21, metadata !DIExpression()), !dbg !27 tail call void @llvm.dbg.value(metadata i64* %start, metadata !22, metadata !DIExpression()), !dbg !28 %0 = load i64, i64* %start, align 4, !dbg !29 @@ -32,12 +46,11 @@ br i1 undef, label %for.end, label %for.body.lr.ph, !dbg !32 for.body.lr.ph: ; preds = %entry - ; The 'load' and the 'add' are sunken to this basic block. So let's verify that the related dbg.values are sunken as well. - ; The add is later eliminated, so we verify that the dbg.value is salvaged by using DW_OP_minus. + ; Check that the load is sunk here; the add is optimised out. Nothing else + ; should be in this block. ; CHECK-LABEL: for.body.lr.ph: ; CHECK-NEXT: %0 = load - ; 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 ! + ; CHECK-NEXT: br label %for.body br label %for.body, !dbg !32 for.body: ; preds = %for.body.lr.ph, %for.body