Skip to content

[DebugInfo][LICM] Salvage dbg_values for the dead instructions to erase #138796

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 12, 2025

Conversation

Apochens
Copy link
Contributor

@Apochens Apochens commented May 7, 2025

fix #138684 .

@llvmbot
Copy link
Member

llvmbot commented May 7, 2025

@llvm/pr-subscribers-debuginfo

Author: Shan Huang (Apochens)

Changes

fix #138684 .


Full diff: https://github.com/llvm/llvm-project/pull/138796.diff

5 Files Affected:

  • (modified) llvm/lib/Transforms/Scalar/LICM.cpp (+12-3)
  • (added) llvm/test/Transforms/LICM/salvage-hoisted-add.ll (+70)
  • (added) llvm/test/Transforms/LICM/salvage-hoisted-binop.ll (+45)
  • (added) llvm/test/Transforms/LICM/salvage-hoisted-gep.ll (+58)
  • (added) llvm/test/Transforms/LICM/salvage-hoisted-sub.ll (+70)
diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index 42bccc858cdaa..62ef40c686874 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -2538,6 +2538,7 @@ static bool hoistGEP(Instruction &I, Loop &L, ICFLoopSafetyInfo &SafetyInfo,
                                     IsInBounds);
   GEP->replaceAllUsesWith(NewGEP);
   eraseInstruction(*GEP, SafetyInfo, MSSAU);
+  salvageDebugInfo(*Src);
   eraseInstruction(*Src, SafetyInfo, MSSAU);
   return true;
 }
@@ -2592,7 +2593,10 @@ static bool hoistAdd(ICmpInst::Predicate Pred, Value *VariantLHS,
   ICmp.setPredicate(Pred);
   ICmp.setOperand(0, VariantOp);
   ICmp.setOperand(1, NewCmpOp);
-  eraseInstruction(cast<Instruction>(*VariantLHS), SafetyInfo, MSSAU);
+
+  Instruction &DeadI = cast<Instruction>(*VariantLHS);
+  salvageDebugInfo(DeadI);
+  eraseInstruction(DeadI, SafetyInfo, MSSAU);
   return true;
 }
 
@@ -2670,7 +2674,10 @@ static bool hoistSub(ICmpInst::Predicate Pred, Value *VariantLHS,
   ICmp.setPredicate(Pred);
   ICmp.setOperand(0, VariantOp);
   ICmp.setOperand(1, NewCmpOp);
-  eraseInstruction(cast<Instruction>(*VariantLHS), SafetyInfo, MSSAU);
+
+  Instruction &DeadI = cast<Instruction>(*VariantLHS);
+  salvageDebugInfo(DeadI);
+  eraseInstruction(DeadI, SafetyInfo, MSSAU);
   return true;
 }
 
@@ -2877,8 +2884,10 @@ static bool hoistBOAssociation(Instruction &I, Loop &L,
 
   // (LV op C1) might not be erased if it has more uses than the one we just
   // replaced.
-  if (BO0->use_empty())
+  if (BO0->use_empty()) {
+    salvageDebugInfo(*BO0);
     eraseInstruction(*BO0, SafetyInfo, MSSAU);
+  }
 
   return true;
 }
diff --git a/llvm/test/Transforms/LICM/salvage-hoisted-add.ll b/llvm/test/Transforms/LICM/salvage-hoisted-add.ll
new file mode 100644
index 0000000000000..1bc5802d5997c
--- /dev/null
+++ b/llvm/test/Transforms/LICM/salvage-hoisted-add.ll
@@ -0,0 +1,70 @@
+; RUN: opt -S -passes=licm %s | FileCheck %s
+
+; Check that hoistAdd() in LICM salvages the dbg_value for the hoisted add
+; instruction.
+
+define i32 @hoist_add(ptr %p, ptr %x_p, ptr %length_p) !dbg !5 {
+; CHECK-LABEL: define i32 @hoist_add(
+; CHECK-LABEL: loop:
+; CHECK:           #dbg_value(!DIArgList(i32 [[X:%.*]], i32 [[IV:%.*]]), [[META9:![0-9]+]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value), [[META16:![0-9]+]])
+;
+entry:
+  %x = load i32, ptr %x_p, align 4, !dbg !20, !range !21
+  %length = load i32, ptr %length_p, align 4, !dbg !22, !range !21
+  br label %loop, !dbg !23
+
+loop:                                             ; preds = %backedge, %entry
+  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ], !dbg !24
+  %arith = add nsw i32 %x, %iv, !dbg !25
+    #dbg_value(i32 %arith, !13, !DIExpression(), !25)
+  %x_check = icmp slt i32 %arith, 4, !dbg !26
+  br i1 %x_check, label %out_of_bounds, label %backedge, !dbg !27
+
+backedge:                                         ; preds = %loop
+  %el.ptr = getelementptr i32, ptr %p, i32 %iv, !dbg !28
+  store i32 1, ptr %el.ptr, align 4, !dbg !29
+  %iv.next = add nuw nsw i32 %iv, 4, !dbg !30
+  %loop_cond = icmp slt i32 %iv.next, %length, !dbg !31
+  br i1 %loop_cond, label %loop, label %exit, !dbg !32
+
+exit:                                             ; preds = %backedge
+  ret i32 %iv.next, !dbg !33
+
+out_of_bounds:                                    ; preds = %loop
+  ret i32 -1, !dbg !34
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.debugify = !{!2, !3}
+!llvm.module.flags = !{!4}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
+!1 = !DIFile(filename: "salvage-hoisted-add", directory: "/")
+!2 = !{i32 14}
+!3 = !{i32 8}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = distinct !DISubprogram(name: "hoist_add", linkageName: "hoist_add", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+!6 = !DISubroutineType(types: !7)
+!7 = !{}
+!8 = !{!13}
+!10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)
+!13 = !DILocalVariable(name: "4", scope: !5, file: !1, line: 5, type: !10)
+!20 = !DILocation(line: 1, column: 1, scope: !5)
+!21 = !{i32 0, i32 -2147483648}
+!22 = !DILocation(line: 2, column: 1, scope: !5)
+!23 = !DILocation(line: 3, column: 1, scope: !5)
+!24 = !DILocation(line: 4, column: 1, scope: !5)
+!25 = !DILocation(line: 5, column: 1, scope: !5)
+!26 = !DILocation(line: 6, column: 1, scope: !5)
+!27 = !DILocation(line: 7, column: 1, scope: !5)
+!28 = !DILocation(line: 8, column: 1, scope: !5)
+!29 = !DILocation(line: 9, column: 1, scope: !5)
+!30 = !DILocation(line: 10, column: 1, scope: !5)
+!31 = !DILocation(line: 11, column: 1, scope: !5)
+!32 = !DILocation(line: 12, column: 1, scope: !5)
+!33 = !DILocation(line: 13, column: 1, scope: !5)
+!34 = !DILocation(line: 14, column: 1, scope: !5)
+;.
+; CHECK: [[META9]] = !DILocalVariable(name: "4",
+; CHECK: [[META16]] = !DILocation(line: 5, column: 1,
+;.
diff --git a/llvm/test/Transforms/LICM/salvage-hoisted-binop.ll b/llvm/test/Transforms/LICM/salvage-hoisted-binop.ll
new file mode 100644
index 0000000000000..97461865c4d79
--- /dev/null
+++ b/llvm/test/Transforms/LICM/salvage-hoisted-binop.ll
@@ -0,0 +1,45 @@
+; RUN: opt -S -passes=licm %s | FileCheck %s
+
+; Check that hoistBOAssociation() in LICM salvages the dbg_value for the
+; hoisted binary operation.
+
+define void @hoist_binop(i64 %c1, i64 %c2) !dbg !5 {
+; CHECK-LABEL: define void @hoist_binop(
+; CHECK-LABEL: loop:
+; CHECK:           #dbg_value(!DIArgList(i64 [[INDEX:%.*]], i64 [[C1:%.*]]), [[META9:![0-9]+]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value), [[META13:![0-9]+]])
+;
+entry:
+  br label %loop, !dbg !13
+
+loop:                                             ; preds = %loop, %entry
+  %index = phi i64 [ 0, %entry ], [ %index.next, %loop ], !dbg !14
+  %step.add = add i64 %index, %c1, !dbg !15
+  #dbg_value(i64 %step.add, !11, !DIExpression(), !15)
+  %index.next = add i64 %step.add, %c2, !dbg !16
+  br label %loop, !dbg !17
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.debugify = !{!2, !3}
+!llvm.module.flags = !{!4}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
+!1 = !DIFile(filename: "salvage-hoist-binop.ll", directory: "/")
+!2 = !{i32 5}
+!3 = !{i32 3}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = distinct !DISubprogram(name: "hoist_binop", linkageName: "hoist_binop", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+!6 = !DISubroutineType(types: !7)
+!7 = !{}
+!8 = !{!11}
+!10 = !DIBasicType(name: "ty64", size: 64, encoding: DW_ATE_unsigned)
+!11 = !DILocalVariable(name: "2", scope: !5, file: !1, line: 3, type: !10)
+!13 = !DILocation(line: 1, column: 1, scope: !5)
+!14 = !DILocation(line: 2, column: 1, scope: !5)
+!15 = !DILocation(line: 3, column: 1, scope: !5)
+!16 = !DILocation(line: 4, column: 1, scope: !5)
+!17 = !DILocation(line: 5, column: 1, scope: !5)
+;.
+; CHECK: [[META9]] = !DILocalVariable(name: "2",
+; CHECK: [[META13]] = !DILocation(line: 3, column: 1,
+;.
diff --git a/llvm/test/Transforms/LICM/salvage-hoisted-gep.ll b/llvm/test/Transforms/LICM/salvage-hoisted-gep.ll
new file mode 100644
index 0000000000000..828a92765b6f3
--- /dev/null
+++ b/llvm/test/Transforms/LICM/salvage-hoisted-gep.ll
@@ -0,0 +1,58 @@
+; RUN: opt -S -passes=licm %s | FileCheck %s
+
+; Check that hoistGEP() in LICM salvages the dbg_value for the hoisted
+; getelementptr instruction.
+
+define void @hoist_gep(ptr %ptr, i1 %c, i32 %arg) !dbg !5 {
+; CHECK-LABEL: define void @hoist_gep(
+; CHECK-LABEL: loop:
+; CHECK:           #dbg_value(!DIArgList(ptr [[PTR:%.*]], i64 [[VAL_EXT:%.*]]), [[META9:![0-9]+]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value), [[META15:![0-9]+]])
+;
+entry:
+  %arg.ext = zext i32 %arg to i64, !dbg !16
+  br label %loop, !dbg !17
+
+loop:                                             ; preds = %loop, %entry
+  %val = call i32 @get.i32(), !dbg !18
+  %val.ext = zext i32 %val to i64, !dbg !19
+  %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext, !dbg !20
+  #dbg_value(ptr %ptr2, !14, !DIExpression(), !20)
+  %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg.ext, !dbg !21
+  call void @use(ptr %ptr3), !dbg !22
+  br i1 %c, label %loop, label %exit, !dbg !23
+
+exit:                                             ; preds = %loop
+  ret void, !dbg !24
+}
+
+declare i32 @get.i32()
+declare void @use(ptr)
+
+!llvm.dbg.cu = !{!0}
+!llvm.debugify = !{!2, !3}
+!llvm.module.flags = !{!4}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
+!1 = !DIFile(filename: "salvage-hoisted-gep.ll", directory: "/")
+!2 = !{i32 9}
+!3 = !{i32 5}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = distinct !DISubprogram(name: "hoist_gep", linkageName: "hoist_gep", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+!6 = !DISubroutineType(types: !7)
+!7 = !{}
+!8 = !{!14}
+!10 = !DIBasicType(name: "ty64", size: 64, encoding: DW_ATE_unsigned)
+!14 = !DILocalVariable(name: "4", scope: !5, file: !1, line: 5, type: !10)
+!16 = !DILocation(line: 1, column: 1, scope: !5)
+!17 = !DILocation(line: 2, column: 1, scope: !5)
+!18 = !DILocation(line: 3, column: 1, scope: !5)
+!19 = !DILocation(line: 4, column: 1, scope: !5)
+!20 = !DILocation(line: 5, column: 1, scope: !5)
+!21 = !DILocation(line: 6, column: 1, scope: !5)
+!22 = !DILocation(line: 7, column: 1, scope: !5)
+!23 = !DILocation(line: 8, column: 1, scope: !5)
+!24 = !DILocation(line: 9, column: 1, scope: !5)
+;.
+; CHECK: [[META9]] = !DILocalVariable(name: "4",
+; CHECK: [[META15]] = !DILocation(line: 5,
+;.
diff --git a/llvm/test/Transforms/LICM/salvage-hoisted-sub.ll b/llvm/test/Transforms/LICM/salvage-hoisted-sub.ll
new file mode 100644
index 0000000000000..854fd102fdf56
--- /dev/null
+++ b/llvm/test/Transforms/LICM/salvage-hoisted-sub.ll
@@ -0,0 +1,70 @@
+; RUN: opt -S -passes=licm %s | FileCheck %s
+
+; Check that hoistSub() in LICM salvages the dbg_value for the hoisted sub
+; instruction.
+
+define i32 @hoist_sub(ptr %p, ptr %x_p, ptr %length_p) !dbg !5 {
+; CHECK-LABEL: define i32 @hoist_sub(
+; CHECK-LABEL: loop:
+; CHECK:           #dbg_value(!DIArgList(i32 [[X:%.*]], i32 [[IV:%.*]]), [[META9:![0-9]+]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_minus, DW_OP_stack_value), [[META16:![0-9]+]])
+;
+entry:
+  %x = load i32, ptr %x_p, align 4, !dbg !20, !range !21
+  %length = load i32, ptr %length_p, align 4, !dbg !22, !range !21
+  br label %loop, !dbg !23
+
+loop:                                             ; preds = %backedge, %entry
+  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ], !dbg !24
+  %arith = sub nsw i32 %x, %iv, !dbg !25
+  #dbg_value(i32 %arith, !13, !DIExpression(), !25)
+  %x_check = icmp slt i32 %arith, 4, !dbg !26
+  br i1 %x_check, label %out_of_bounds, label %backedge, !dbg !27
+
+backedge:                                         ; preds = %loop
+  %el.ptr = getelementptr i32, ptr %p, i32 %iv, !dbg !28
+  store i32 1, ptr %el.ptr, align 4, !dbg !29
+  %iv.next = add nuw nsw i32 %iv, 4, !dbg !30
+  %loop_cond = icmp slt i32 %iv.next, %length, !dbg !31
+  br i1 %loop_cond, label %loop, label %exit, !dbg !32
+
+exit:                                             ; preds = %backedge
+  ret i32 %iv.next, !dbg !33
+
+out_of_bounds:                                    ; preds = %loop
+  ret i32 -1, !dbg !34
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.debugify = !{!2, !3}
+!llvm.module.flags = !{!4}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
+!1 = !DIFile(filename: "salvage-hoisted-sub.ll", directory: "/")
+!2 = !{i32 14}
+!3 = !{i32 8}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = distinct !DISubprogram(name: "hoist_sub", linkageName: "hoist_sub", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+!6 = !DISubroutineType(types: !7)
+!7 = !{}
+!8 = !{!13}
+!10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)
+!13 = !DILocalVariable(name: "4", scope: !5, file: !1, line: 5, type: !10)
+!20 = !DILocation(line: 1, column: 1, scope: !5)
+!21 = !{i32 0, i32 -2147483648}
+!22 = !DILocation(line: 2, column: 1, scope: !5)
+!23 = !DILocation(line: 3, column: 1, scope: !5)
+!24 = !DILocation(line: 4, column: 1, scope: !5)
+!25 = !DILocation(line: 5, column: 1, scope: !5)
+!26 = !DILocation(line: 6, column: 1, scope: !5)
+!27 = !DILocation(line: 7, column: 1, scope: !5)
+!28 = !DILocation(line: 8, column: 1, scope: !5)
+!29 = !DILocation(line: 9, column: 1, scope: !5)
+!30 = !DILocation(line: 10, column: 1, scope: !5)
+!31 = !DILocation(line: 11, column: 1, scope: !5)
+!32 = !DILocation(line: 12, column: 1, scope: !5)
+!33 = !DILocation(line: 13, column: 1, scope: !5)
+!34 = !DILocation(line: 14, column: 1, scope: !5)
+;.
+; CHECK: [[META9]] = !DILocalVariable(name: "4",
+; CHECK: [[META16]] = !DILocation(line: 5, column: 1,
+;.

@llvmbot
Copy link
Member

llvmbot commented May 7, 2025

@llvm/pr-subscribers-llvm-transforms

Author: Shan Huang (Apochens)

Changes

fix #138684 .


Full diff: https://github.com/llvm/llvm-project/pull/138796.diff

5 Files Affected:

  • (modified) llvm/lib/Transforms/Scalar/LICM.cpp (+12-3)
  • (added) llvm/test/Transforms/LICM/salvage-hoisted-add.ll (+70)
  • (added) llvm/test/Transforms/LICM/salvage-hoisted-binop.ll (+45)
  • (added) llvm/test/Transforms/LICM/salvage-hoisted-gep.ll (+58)
  • (added) llvm/test/Transforms/LICM/salvage-hoisted-sub.ll (+70)
diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index 42bccc858cdaa..62ef40c686874 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -2538,6 +2538,7 @@ static bool hoistGEP(Instruction &I, Loop &L, ICFLoopSafetyInfo &SafetyInfo,
                                     IsInBounds);
   GEP->replaceAllUsesWith(NewGEP);
   eraseInstruction(*GEP, SafetyInfo, MSSAU);
+  salvageDebugInfo(*Src);
   eraseInstruction(*Src, SafetyInfo, MSSAU);
   return true;
 }
@@ -2592,7 +2593,10 @@ static bool hoistAdd(ICmpInst::Predicate Pred, Value *VariantLHS,
   ICmp.setPredicate(Pred);
   ICmp.setOperand(0, VariantOp);
   ICmp.setOperand(1, NewCmpOp);
-  eraseInstruction(cast<Instruction>(*VariantLHS), SafetyInfo, MSSAU);
+
+  Instruction &DeadI = cast<Instruction>(*VariantLHS);
+  salvageDebugInfo(DeadI);
+  eraseInstruction(DeadI, SafetyInfo, MSSAU);
   return true;
 }
 
@@ -2670,7 +2674,10 @@ static bool hoistSub(ICmpInst::Predicate Pred, Value *VariantLHS,
   ICmp.setPredicate(Pred);
   ICmp.setOperand(0, VariantOp);
   ICmp.setOperand(1, NewCmpOp);
-  eraseInstruction(cast<Instruction>(*VariantLHS), SafetyInfo, MSSAU);
+
+  Instruction &DeadI = cast<Instruction>(*VariantLHS);
+  salvageDebugInfo(DeadI);
+  eraseInstruction(DeadI, SafetyInfo, MSSAU);
   return true;
 }
 
@@ -2877,8 +2884,10 @@ static bool hoistBOAssociation(Instruction &I, Loop &L,
 
   // (LV op C1) might not be erased if it has more uses than the one we just
   // replaced.
-  if (BO0->use_empty())
+  if (BO0->use_empty()) {
+    salvageDebugInfo(*BO0);
     eraseInstruction(*BO0, SafetyInfo, MSSAU);
+  }
 
   return true;
 }
diff --git a/llvm/test/Transforms/LICM/salvage-hoisted-add.ll b/llvm/test/Transforms/LICM/salvage-hoisted-add.ll
new file mode 100644
index 0000000000000..1bc5802d5997c
--- /dev/null
+++ b/llvm/test/Transforms/LICM/salvage-hoisted-add.ll
@@ -0,0 +1,70 @@
+; RUN: opt -S -passes=licm %s | FileCheck %s
+
+; Check that hoistAdd() in LICM salvages the dbg_value for the hoisted add
+; instruction.
+
+define i32 @hoist_add(ptr %p, ptr %x_p, ptr %length_p) !dbg !5 {
+; CHECK-LABEL: define i32 @hoist_add(
+; CHECK-LABEL: loop:
+; CHECK:           #dbg_value(!DIArgList(i32 [[X:%.*]], i32 [[IV:%.*]]), [[META9:![0-9]+]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value), [[META16:![0-9]+]])
+;
+entry:
+  %x = load i32, ptr %x_p, align 4, !dbg !20, !range !21
+  %length = load i32, ptr %length_p, align 4, !dbg !22, !range !21
+  br label %loop, !dbg !23
+
+loop:                                             ; preds = %backedge, %entry
+  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ], !dbg !24
+  %arith = add nsw i32 %x, %iv, !dbg !25
+    #dbg_value(i32 %arith, !13, !DIExpression(), !25)
+  %x_check = icmp slt i32 %arith, 4, !dbg !26
+  br i1 %x_check, label %out_of_bounds, label %backedge, !dbg !27
+
+backedge:                                         ; preds = %loop
+  %el.ptr = getelementptr i32, ptr %p, i32 %iv, !dbg !28
+  store i32 1, ptr %el.ptr, align 4, !dbg !29
+  %iv.next = add nuw nsw i32 %iv, 4, !dbg !30
+  %loop_cond = icmp slt i32 %iv.next, %length, !dbg !31
+  br i1 %loop_cond, label %loop, label %exit, !dbg !32
+
+exit:                                             ; preds = %backedge
+  ret i32 %iv.next, !dbg !33
+
+out_of_bounds:                                    ; preds = %loop
+  ret i32 -1, !dbg !34
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.debugify = !{!2, !3}
+!llvm.module.flags = !{!4}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
+!1 = !DIFile(filename: "salvage-hoisted-add", directory: "/")
+!2 = !{i32 14}
+!3 = !{i32 8}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = distinct !DISubprogram(name: "hoist_add", linkageName: "hoist_add", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+!6 = !DISubroutineType(types: !7)
+!7 = !{}
+!8 = !{!13}
+!10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)
+!13 = !DILocalVariable(name: "4", scope: !5, file: !1, line: 5, type: !10)
+!20 = !DILocation(line: 1, column: 1, scope: !5)
+!21 = !{i32 0, i32 -2147483648}
+!22 = !DILocation(line: 2, column: 1, scope: !5)
+!23 = !DILocation(line: 3, column: 1, scope: !5)
+!24 = !DILocation(line: 4, column: 1, scope: !5)
+!25 = !DILocation(line: 5, column: 1, scope: !5)
+!26 = !DILocation(line: 6, column: 1, scope: !5)
+!27 = !DILocation(line: 7, column: 1, scope: !5)
+!28 = !DILocation(line: 8, column: 1, scope: !5)
+!29 = !DILocation(line: 9, column: 1, scope: !5)
+!30 = !DILocation(line: 10, column: 1, scope: !5)
+!31 = !DILocation(line: 11, column: 1, scope: !5)
+!32 = !DILocation(line: 12, column: 1, scope: !5)
+!33 = !DILocation(line: 13, column: 1, scope: !5)
+!34 = !DILocation(line: 14, column: 1, scope: !5)
+;.
+; CHECK: [[META9]] = !DILocalVariable(name: "4",
+; CHECK: [[META16]] = !DILocation(line: 5, column: 1,
+;.
diff --git a/llvm/test/Transforms/LICM/salvage-hoisted-binop.ll b/llvm/test/Transforms/LICM/salvage-hoisted-binop.ll
new file mode 100644
index 0000000000000..97461865c4d79
--- /dev/null
+++ b/llvm/test/Transforms/LICM/salvage-hoisted-binop.ll
@@ -0,0 +1,45 @@
+; RUN: opt -S -passes=licm %s | FileCheck %s
+
+; Check that hoistBOAssociation() in LICM salvages the dbg_value for the
+; hoisted binary operation.
+
+define void @hoist_binop(i64 %c1, i64 %c2) !dbg !5 {
+; CHECK-LABEL: define void @hoist_binop(
+; CHECK-LABEL: loop:
+; CHECK:           #dbg_value(!DIArgList(i64 [[INDEX:%.*]], i64 [[C1:%.*]]), [[META9:![0-9]+]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value), [[META13:![0-9]+]])
+;
+entry:
+  br label %loop, !dbg !13
+
+loop:                                             ; preds = %loop, %entry
+  %index = phi i64 [ 0, %entry ], [ %index.next, %loop ], !dbg !14
+  %step.add = add i64 %index, %c1, !dbg !15
+  #dbg_value(i64 %step.add, !11, !DIExpression(), !15)
+  %index.next = add i64 %step.add, %c2, !dbg !16
+  br label %loop, !dbg !17
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.debugify = !{!2, !3}
+!llvm.module.flags = !{!4}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
+!1 = !DIFile(filename: "salvage-hoist-binop.ll", directory: "/")
+!2 = !{i32 5}
+!3 = !{i32 3}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = distinct !DISubprogram(name: "hoist_binop", linkageName: "hoist_binop", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+!6 = !DISubroutineType(types: !7)
+!7 = !{}
+!8 = !{!11}
+!10 = !DIBasicType(name: "ty64", size: 64, encoding: DW_ATE_unsigned)
+!11 = !DILocalVariable(name: "2", scope: !5, file: !1, line: 3, type: !10)
+!13 = !DILocation(line: 1, column: 1, scope: !5)
+!14 = !DILocation(line: 2, column: 1, scope: !5)
+!15 = !DILocation(line: 3, column: 1, scope: !5)
+!16 = !DILocation(line: 4, column: 1, scope: !5)
+!17 = !DILocation(line: 5, column: 1, scope: !5)
+;.
+; CHECK: [[META9]] = !DILocalVariable(name: "2",
+; CHECK: [[META13]] = !DILocation(line: 3, column: 1,
+;.
diff --git a/llvm/test/Transforms/LICM/salvage-hoisted-gep.ll b/llvm/test/Transforms/LICM/salvage-hoisted-gep.ll
new file mode 100644
index 0000000000000..828a92765b6f3
--- /dev/null
+++ b/llvm/test/Transforms/LICM/salvage-hoisted-gep.ll
@@ -0,0 +1,58 @@
+; RUN: opt -S -passes=licm %s | FileCheck %s
+
+; Check that hoistGEP() in LICM salvages the dbg_value for the hoisted
+; getelementptr instruction.
+
+define void @hoist_gep(ptr %ptr, i1 %c, i32 %arg) !dbg !5 {
+; CHECK-LABEL: define void @hoist_gep(
+; CHECK-LABEL: loop:
+; CHECK:           #dbg_value(!DIArgList(ptr [[PTR:%.*]], i64 [[VAL_EXT:%.*]]), [[META9:![0-9]+]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value), [[META15:![0-9]+]])
+;
+entry:
+  %arg.ext = zext i32 %arg to i64, !dbg !16
+  br label %loop, !dbg !17
+
+loop:                                             ; preds = %loop, %entry
+  %val = call i32 @get.i32(), !dbg !18
+  %val.ext = zext i32 %val to i64, !dbg !19
+  %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext, !dbg !20
+  #dbg_value(ptr %ptr2, !14, !DIExpression(), !20)
+  %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg.ext, !dbg !21
+  call void @use(ptr %ptr3), !dbg !22
+  br i1 %c, label %loop, label %exit, !dbg !23
+
+exit:                                             ; preds = %loop
+  ret void, !dbg !24
+}
+
+declare i32 @get.i32()
+declare void @use(ptr)
+
+!llvm.dbg.cu = !{!0}
+!llvm.debugify = !{!2, !3}
+!llvm.module.flags = !{!4}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
+!1 = !DIFile(filename: "salvage-hoisted-gep.ll", directory: "/")
+!2 = !{i32 9}
+!3 = !{i32 5}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = distinct !DISubprogram(name: "hoist_gep", linkageName: "hoist_gep", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+!6 = !DISubroutineType(types: !7)
+!7 = !{}
+!8 = !{!14}
+!10 = !DIBasicType(name: "ty64", size: 64, encoding: DW_ATE_unsigned)
+!14 = !DILocalVariable(name: "4", scope: !5, file: !1, line: 5, type: !10)
+!16 = !DILocation(line: 1, column: 1, scope: !5)
+!17 = !DILocation(line: 2, column: 1, scope: !5)
+!18 = !DILocation(line: 3, column: 1, scope: !5)
+!19 = !DILocation(line: 4, column: 1, scope: !5)
+!20 = !DILocation(line: 5, column: 1, scope: !5)
+!21 = !DILocation(line: 6, column: 1, scope: !5)
+!22 = !DILocation(line: 7, column: 1, scope: !5)
+!23 = !DILocation(line: 8, column: 1, scope: !5)
+!24 = !DILocation(line: 9, column: 1, scope: !5)
+;.
+; CHECK: [[META9]] = !DILocalVariable(name: "4",
+; CHECK: [[META15]] = !DILocation(line: 5,
+;.
diff --git a/llvm/test/Transforms/LICM/salvage-hoisted-sub.ll b/llvm/test/Transforms/LICM/salvage-hoisted-sub.ll
new file mode 100644
index 0000000000000..854fd102fdf56
--- /dev/null
+++ b/llvm/test/Transforms/LICM/salvage-hoisted-sub.ll
@@ -0,0 +1,70 @@
+; RUN: opt -S -passes=licm %s | FileCheck %s
+
+; Check that hoistSub() in LICM salvages the dbg_value for the hoisted sub
+; instruction.
+
+define i32 @hoist_sub(ptr %p, ptr %x_p, ptr %length_p) !dbg !5 {
+; CHECK-LABEL: define i32 @hoist_sub(
+; CHECK-LABEL: loop:
+; CHECK:           #dbg_value(!DIArgList(i32 [[X:%.*]], i32 [[IV:%.*]]), [[META9:![0-9]+]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_minus, DW_OP_stack_value), [[META16:![0-9]+]])
+;
+entry:
+  %x = load i32, ptr %x_p, align 4, !dbg !20, !range !21
+  %length = load i32, ptr %length_p, align 4, !dbg !22, !range !21
+  br label %loop, !dbg !23
+
+loop:                                             ; preds = %backedge, %entry
+  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ], !dbg !24
+  %arith = sub nsw i32 %x, %iv, !dbg !25
+  #dbg_value(i32 %arith, !13, !DIExpression(), !25)
+  %x_check = icmp slt i32 %arith, 4, !dbg !26
+  br i1 %x_check, label %out_of_bounds, label %backedge, !dbg !27
+
+backedge:                                         ; preds = %loop
+  %el.ptr = getelementptr i32, ptr %p, i32 %iv, !dbg !28
+  store i32 1, ptr %el.ptr, align 4, !dbg !29
+  %iv.next = add nuw nsw i32 %iv, 4, !dbg !30
+  %loop_cond = icmp slt i32 %iv.next, %length, !dbg !31
+  br i1 %loop_cond, label %loop, label %exit, !dbg !32
+
+exit:                                             ; preds = %backedge
+  ret i32 %iv.next, !dbg !33
+
+out_of_bounds:                                    ; preds = %loop
+  ret i32 -1, !dbg !34
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.debugify = !{!2, !3}
+!llvm.module.flags = !{!4}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
+!1 = !DIFile(filename: "salvage-hoisted-sub.ll", directory: "/")
+!2 = !{i32 14}
+!3 = !{i32 8}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = distinct !DISubprogram(name: "hoist_sub", linkageName: "hoist_sub", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+!6 = !DISubroutineType(types: !7)
+!7 = !{}
+!8 = !{!13}
+!10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)
+!13 = !DILocalVariable(name: "4", scope: !5, file: !1, line: 5, type: !10)
+!20 = !DILocation(line: 1, column: 1, scope: !5)
+!21 = !{i32 0, i32 -2147483648}
+!22 = !DILocation(line: 2, column: 1, scope: !5)
+!23 = !DILocation(line: 3, column: 1, scope: !5)
+!24 = !DILocation(line: 4, column: 1, scope: !5)
+!25 = !DILocation(line: 5, column: 1, scope: !5)
+!26 = !DILocation(line: 6, column: 1, scope: !5)
+!27 = !DILocation(line: 7, column: 1, scope: !5)
+!28 = !DILocation(line: 8, column: 1, scope: !5)
+!29 = !DILocation(line: 9, column: 1, scope: !5)
+!30 = !DILocation(line: 10, column: 1, scope: !5)
+!31 = !DILocation(line: 11, column: 1, scope: !5)
+!32 = !DILocation(line: 12, column: 1, scope: !5)
+!33 = !DILocation(line: 13, column: 1, scope: !5)
+!34 = !DILocation(line: 14, column: 1, scope: !5)
+;.
+; CHECK: [[META9]] = !DILocalVariable(name: "4",
+; CHECK: [[META16]] = !DILocation(line: 5, column: 1,
+;.

Copy link
Contributor

@OCHyams OCHyams left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

loop: ; preds = %loop, %entry
%index = phi i64 [ 0, %entry ], [ %index.next, %loop ], !dbg !14
%step.add = add i64 %index, %c1, !dbg !15
#dbg_value(i64 %step.add, !11, !DIExpression(), !15)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: please can you indent the #dbg_value, same in the other tests below (sorry to be annoying).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry 😢 I found out that the #dbg_values without the indentations are generated after using the helper script update_test_checks.py. I'll fix them now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, that's annoying for it to do that. I'm not very familiar with the script but I'll try and fix that (#139230).

(Patch still LGTM, ty)

@Apochens Apochens merged commit 5971b41 into llvm:main May 12, 2025
11 checks passed
@Apochens Apochens deleted the #138684-licm-salvage-dbg-value branch May 12, 2025 01:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[DebugInfo][LICM] Debug value info loss caused by removing dead instructions without salvaging
3 participants