[llvm] [indvars] Missing variables at Og (PR #88270)

Carlos Alberto Enciso via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 10 21:12:08 PDT 2024


https://github.com/CarlosAlbertoEnciso updated https://github.com/llvm/llvm-project/pull/88270

>From fdd13d96ac043cdaf425d3a9b4b10997cc5bd365 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <carlos.alberto.enciso at gmail.com>
Date: Mon, 23 Oct 2023 11:44:22 +0100
Subject: [PATCH 01/11] [indvars] Missing variables at Og:

https://bugs.llvm.org/show_bug.cgi?id=51735
https://github.com/llvm/llvm-project/issues/51077

In the given test case:

 4 ...
 5 void bar() {
 6   int End = 777;
 7   int Index = 27;
 8   char Var = 1;
 9   for (; Index < End; ++Index)
10     ;
11   nop(Index);
12 }
13 ...

Missing local variable 'Index' after loop 'Induction Variable Elimination'.
When adding a breakpoint at line 11, LLDB does not have information on
the variable. But it has info on 'Var' and 'End'.
---
 llvm/lib/Transforms/Scalar/IndVarSimplify.cpp |  25 ++++
 .../test/Transforms/LoopSimplify/pr51735-1.ll | 115 ++++++++++++++++++
 llvm/test/Transforms/LoopSimplify/pr51735.ll  | 106 ++++++++++++++++
 3 files changed, 246 insertions(+)
 create mode 100644 llvm/test/Transforms/LoopSimplify/pr51735-1.ll
 create mode 100644 llvm/test/Transforms/LoopSimplify/pr51735.ll

diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
index 41c4d623617347..0e20b5e6204037 100644
--- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
+++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
@@ -46,6 +46,7 @@
 #include "llvm/IR/ConstantRange.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/Function.h"
@@ -1931,6 +1932,30 @@ bool IndVarSimplify::run(Loop *L) {
     }
   }
 
+  // The loop exit values have been updated; insert the debug location
+  // for the induction variable with its final value.
+  if (PHINode *IndVar = L->getInductionVariable(*SE)) {
+    const SCEV *IndVarSCEV = SE->getSCEVAtScope(IndVar, L->getParentLoop());
+    if (IndVarSCEV->getSCEVType() == SCEVTypes::scConstant) {
+      Value *FinalIVValue = cast<SCEVConstant>(IndVarSCEV)->getValue();
+      SmallVector<DbgVariableIntrinsic *> DbgUsers;
+      SmallVector<DbgVariableIntrinsic *> DbgUsersCloned;
+      findDbgUsers(DbgUsers, IndVar);
+      for (auto &DebugUser : DbgUsers) {
+        auto *Cloned = cast<DbgVariableIntrinsic>(DebugUser->clone());
+        Cloned->replaceVariableLocationOp(static_cast<unsigned>(0),
+                                          FinalIVValue);
+        DbgUsersCloned.push_back(Cloned);
+      }
+
+      SmallVector<BasicBlock *> ExitBlocks;
+      L->getExitBlocks(ExitBlocks);
+      for (BasicBlock *Exit : ExitBlocks)
+        for (auto &DebugUser : DbgUsersCloned)
+          DebugUser->insertBefore(Exit->getFirstNonPHI());
+    }
+  }
+
   // Eliminate redundant IV cycles.
   NumElimIV += Rewriter.replaceCongruentIVs(L, DT, DeadInsts, TTI);
 
diff --git a/llvm/test/Transforms/LoopSimplify/pr51735-1.ll b/llvm/test/Transforms/LoopSimplify/pr51735-1.ll
new file mode 100644
index 00000000000000..de9a7452209565
--- /dev/null
+++ b/llvm/test/Transforms/LoopSimplify/pr51735-1.ll
@@ -0,0 +1,115 @@
+; RUN: opt -passes=indvars -S -o - < %s | FileCheck %s
+
+; Missing local variable 'Index' after loop 'Induction Variable Elimination'.
+; When adding a breakpoint at line 11, LLDB does not have information on
+; the variable. But it has info on 'Var' and 'End'.
+
+;  1	__attribute__((optnone)) int nop(int Param) {
+;  2	  return 0;
+;  3	}
+;  4
+;  5	void bar() {
+;  6    int End = 777;
+;  7	  int Index = 27;
+;  8	  char Var = 1;
+;  9	  for (; Index < End; ++Index)
+; 10	    ;
+; 11	  nop(Index);
+; 12	}
+; 13
+; 14	int main () {
+; 15	  bar();
+; 16	}
+
+; CHECK: for.cond: {{.*}}
+; CHECK:   call void @llvm.dbg.value(metadata i32 poison, metadata ![[DBG:[0-9]+]], {{.*}}
+; CHECK:   call void @llvm.dbg.value(metadata i32 poison, metadata ![[DBG:[0-9]+]], {{.*}}
+; CHECK:   br i1 false, label %for.cond, label %for.end, {{.*}}
+; CHECK: for.end: {{.*}}
+; CHECK:   call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG:[0-9]+]], {{.*}}
+; CHECK:   %call = tail call noundef i32 @_Z3nopi(i32 noundef 777), {{.*}}
+; CHECK-DAG: ![[DBG]] = !DILocalVariable(name: "Index"{{.*}})
+
+define dso_local noundef i32 @_Z3nopi(i32 noundef %Param) local_unnamed_addr #0 !dbg !10 {
+entry:
+  %Param.addr = alloca i32, align 4
+  store i32 %Param, ptr %Param.addr, align 4
+  call void @llvm.dbg.declare(metadata ptr %Param.addr, metadata !15, metadata !DIExpression()), !dbg !16
+  ret i32 0, !dbg !17
+}
+
+define dso_local void @_Z3barv() local_unnamed_addr #2 !dbg !18 {
+entry:
+  call void @llvm.dbg.value(metadata i32 777, metadata !21, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i32 27, metadata !23, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.value(metadata i32 1, metadata !24, metadata !DIExpression()), !dbg !22
+  br label %for.cond, !dbg !25
+
+for.cond:                                         ; preds = %for.cond, %entry
+  %Index.0 = phi i32 [ 27, %entry ], [ %inc, %for.cond ], !dbg !22
+  call void @llvm.dbg.value(metadata i32 %Index.0, metadata !23, metadata !DIExpression()), !dbg !22
+  %cmp = icmp ult i32 %Index.0, 777, !dbg !26
+  %inc = add nuw nsw i32 %Index.0, 1, !dbg !29
+  call void @llvm.dbg.value(metadata i32 %inc, metadata !23, metadata !DIExpression()), !dbg !22
+  br i1 %cmp, label %for.cond, label %for.end, !dbg !30, !llvm.loop !31
+
+for.end:                                          ; preds = %for.cond
+  %Index.0.lcssa = phi i32 [ %Index.0, %for.cond ], !dbg !22
+  %call = tail call noundef i32 @_Z3nopi(i32 noundef %Index.0.lcssa), !dbg !34
+  ret void, !dbg !35
+}
+
+define dso_local noundef i32 @main() local_unnamed_addr #3 !dbg !36 {
+entry:
+  call void @_Z3barv(), !dbg !39
+  ret i32 0, !dbg !40
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 18.0.0 (https://github.com/llvm/llvm-project.git 18c2eb2bf02bd7666523aa566e45d62053b7db80)", 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}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"PIE Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{i32 7, !"frame-pointer", i32 2}
+!9 = !{!"clang version 18.0.0"}
+!10 = distinct !DISubprogram(name: "nop", linkageName: "_Z3nopi", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14)
+!11 = !DISubroutineType(types: !12)
+!12 = !{!13, !13}
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!14 = !{}
+!15 = !DILocalVariable(name: "Param", arg: 1, scope: !10, file: !1, line: 1, type: !13)
+!16 = !DILocation(line: 1, column: 38, scope: !10)
+!17 = !DILocation(line: 2, column: 3, scope: !10)
+!18 = distinct !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 5, type: !19, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14)
+!19 = !DISubroutineType(types: !20)
+!20 = !{null}
+!21 = !DILocalVariable(name: "End", scope: !18, file: !1, line: 6, type: !13)
+!22 = !DILocation(line: 0, scope: !18)
+!23 = !DILocalVariable(name: "Index", scope: !18, file: !1, line: 7, type: !13)
+!24 = !DILocalVariable(name: "Var", scope: !18, file: !1, line: 8, type: !13)
+!25 = !DILocation(line: 9, column: 3, scope: !18)
+!26 = !DILocation(line: 9, column: 16, scope: !27)
+!27 = distinct !DILexicalBlock(scope: !28, file: !1, line: 9, column: 3)
+!28 = distinct !DILexicalBlock(scope: !18, file: !1, line: 9, column: 3)
+!29 = !DILocation(line: 9, column: 23, scope: !27)
+!30 = !DILocation(line: 9, column: 3, scope: !28)
+!31 = distinct !{!31, !30, !32, !33}
+!32 = !DILocation(line: 10, column: 5, scope: !28)
+!33 = !{!"llvm.loop.mustprogress"}
+!34 = !DILocation(line: 11, column: 3, scope: !18)
+!35 = !DILocation(line: 12, column: 1, scope: !18)
+!36 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 14, type: !37, scopeLine: 14, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
+!37 = !DISubroutineType(types: !38)
+!38 = !{!13}
+!39 = !DILocation(line: 15, column: 3, scope: !36)
+!40 = !DILocation(line: 16, column: 1, scope: !36)
diff --git a/llvm/test/Transforms/LoopSimplify/pr51735.ll b/llvm/test/Transforms/LoopSimplify/pr51735.ll
new file mode 100644
index 00000000000000..b9bdc8ca1b6fb0
--- /dev/null
+++ b/llvm/test/Transforms/LoopSimplify/pr51735.ll
@@ -0,0 +1,106 @@
+; RUN: opt -passes=indvars -S -o - < %s | FileCheck %s
+
+; Missing local variable 'Index' after loop 'Induction Variable Elimination'.
+; When adding a breakpoint at line 11, LLDB does not have information on
+; the variable. But it has info on 'Var' and 'End'.
+
+;  1	__attribute__((optnone)) int nop() {
+;  2	  return 0;
+;  3	}
+;  4
+;  5	void bar() {
+;  6    int End = 777;
+;  7	  int Index = 27;
+;  8	  char Var = 1;
+;  9	  for (; Index < End; ++Index)
+; 10	    ;
+; 11	  nop();
+; 12	}
+; 13
+; 14	int main () {
+; 15	  bar();
+; 16	}
+
+; CHECK: for.cond: {{.*}}
+; CHECK:   call void @llvm.dbg.value(metadata i32 poison, metadata ![[DBG:[0-9]+]], {{.*}}
+; CHECK:   call void @llvm.dbg.value(metadata i32 poison, metadata ![[DBG:[0-9]+]], {{.*}}
+; CHECK:   br i1 false, label %for.cond, label %for.end, {{.*}}
+; CHECK: for.end: {{.*}}
+; CHECK:   call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG:[0-9]+]], {{.*}}
+; CHECK:   %call = tail call noundef i32 @_Z3nopv(), {{.*}}
+; CHECK-DAG: ![[DBG]] = !DILocalVariable(name: "Index"{{.*}})
+
+define dso_local noundef i32 @_Z3nopv() local_unnamed_addr #0 !dbg !10 {
+entry:
+  ret i32 0, !dbg !14
+}
+
+define dso_local void @_Z3barv() local_unnamed_addr #1 !dbg !15 {
+entry:
+  call void @llvm.dbg.value(metadata i32 777, metadata !19, metadata !DIExpression()), !dbg !20
+  call void @llvm.dbg.value(metadata i32 27, metadata !21, metadata !DIExpression()), !dbg !20
+  call void @llvm.dbg.value(metadata i32 1, metadata !22, metadata !DIExpression()), !dbg !20
+  br label %for.cond, !dbg !23
+
+for.cond:                                         ; preds = %for.cond, %entry
+  %Index.0 = phi i32 [ 27, %entry ], [ %inc, %for.cond ], !dbg !20
+  call void @llvm.dbg.value(metadata i32 %Index.0, metadata !21, metadata !DIExpression()), !dbg !20
+  %cmp = icmp ult i32 %Index.0, 777, !dbg !24
+  %inc = add nuw nsw i32 %Index.0, 1, !dbg !27
+  call void @llvm.dbg.value(metadata i32 %inc, metadata !21, metadata !DIExpression()), !dbg !20
+  br i1 %cmp, label %for.cond, label %for.end, !dbg !28, !llvm.loop !29
+
+for.end:                                          ; preds = %for.cond
+  %call = tail call noundef i32 @_Z3nopv(), !dbg !32
+  ret void, !dbg !33
+}
+
+define dso_local noundef i32 @main() local_unnamed_addr #2 !dbg !34 {
+entry:
+  call void @_Z3barv(), !dbg !35
+  ret i32 0, !dbg !36
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 18.0.0 (https://github.com/llvm/llvm-project.git 18c2eb2bf02bd7666523aa566e45d62053b7db80)", 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}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"PIE Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{i32 7, !"frame-pointer", i32 2}
+!9 = !{!"clang version 18.0.0"}
+!10 = distinct !DISubprogram(name: "nop", linkageName: "_Z3nopv", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
+!11 = !DISubroutineType(types: !12)
+!12 = !{!13}
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!14 = !DILocation(line: 2, column: 3, scope: !10)
+!15 = distinct !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 5, type: !16, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !18)
+!16 = !DISubroutineType(types: !17)
+!17 = !{null}
+!18 = !{}
+!19 = !DILocalVariable(name: "End", scope: !15, file: !1, line: 6, type: !13)
+!20 = !DILocation(line: 0, scope: !15)
+!21 = !DILocalVariable(name: "Index", scope: !15, file: !1, line: 7, type: !13)
+!22 = !DILocalVariable(name: "Var", scope: !15, file: !1, line: 8, type: !13)
+!23 = !DILocation(line: 9, column: 3, scope: !15)
+!24 = !DILocation(line: 9, column: 16, scope: !25)
+!25 = distinct !DILexicalBlock(scope: !26, file: !1, line: 9, column: 3)
+!26 = distinct !DILexicalBlock(scope: !15, file: !1, line: 9, column: 3)
+!27 = !DILocation(line: 9, column: 23, scope: !25)
+!28 = !DILocation(line: 9, column: 3, scope: !26)
+!29 = distinct !{!29, !28, !30, !31}
+!30 = !DILocation(line: 10, column: 5, scope: !26)
+!31 = !{!"llvm.loop.mustprogress"}
+!32 = !DILocation(line: 11, column: 3, scope: !15)
+!33 = !DILocation(line: 12, column: 1, scope: !15)
+!34 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 14, type: !11, scopeLine: 14, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
+!35 = !DILocation(line: 15, column: 3, scope: !34)
+!36 = !DILocation(line: 16, column: 1, scope: !34)

>From a6260d4dc637348348b5d62e12633448ff905b3b Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <carlos.alberto.enciso at gmail.com>
Date: Thu, 26 Oct 2023 06:56:46 +0100
Subject: [PATCH 02/11] [indvars] Missing variables at Og:

https://bugs.llvm.org/show_bug.cgi?id=51735
https://github.com/llvm/llvm-project/issues/51077

In the given test case:

 4 ...
 5 void bar() {
 6   int End = 777;
 7   int Index = 27;
 8   char Var = 1;
 9   for (; Index < End; ++Index)
10     ;
11   nop(Index);
12 }
13 ...

Missing local variable 'Index' after loop 'Induction Variable Elimination'.
When adding a breakpoint at line 11, LLDB does not have information on
the variable. But it has info on 'Var' and 'End'.

- Moved the new logic to 'rewriteLoopExitValues'.
- Removed from the test cases, the unrelated functions: 'nop' and 'main'.
- Use 'isa<SCEVConstant>'.
---
 llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 24 -------------
 llvm/lib/Transforms/Utils/LoopUtils.cpp       | 26 ++++++++++++++
 .../test/Transforms/LoopSimplify/pr51735-1.ll | 34 ++-----------------
 llvm/test/Transforms/LoopSimplify/pr51735.ll  | 23 +------------
 4 files changed, 30 insertions(+), 77 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
index 0e20b5e6204037..2a6997c48883d4 100644
--- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
+++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
@@ -1932,30 +1932,6 @@ bool IndVarSimplify::run(Loop *L) {
     }
   }
 
-  // The loop exit values have been updated; insert the debug location
-  // for the induction variable with its final value.
-  if (PHINode *IndVar = L->getInductionVariable(*SE)) {
-    const SCEV *IndVarSCEV = SE->getSCEVAtScope(IndVar, L->getParentLoop());
-    if (IndVarSCEV->getSCEVType() == SCEVTypes::scConstant) {
-      Value *FinalIVValue = cast<SCEVConstant>(IndVarSCEV)->getValue();
-      SmallVector<DbgVariableIntrinsic *> DbgUsers;
-      SmallVector<DbgVariableIntrinsic *> DbgUsersCloned;
-      findDbgUsers(DbgUsers, IndVar);
-      for (auto &DebugUser : DbgUsers) {
-        auto *Cloned = cast<DbgVariableIntrinsic>(DebugUser->clone());
-        Cloned->replaceVariableLocationOp(static_cast<unsigned>(0),
-                                          FinalIVValue);
-        DbgUsersCloned.push_back(Cloned);
-      }
-
-      SmallVector<BasicBlock *> ExitBlocks;
-      L->getExitBlocks(ExitBlocks);
-      for (BasicBlock *Exit : ExitBlocks)
-        for (auto &DebugUser : DbgUsersCloned)
-          DebugUser->insertBefore(Exit->getFirstNonPHI());
-    }
-  }
-
   // Eliminate redundant IV cycles.
   NumElimIV += Rewriter.replaceCongruentIVs(L, DT, DeadInsts, TTI);
 
diff --git a/llvm/lib/Transforms/Utils/LoopUtils.cpp b/llvm/lib/Transforms/Utils/LoopUtils.cpp
index 002bc90c9b5677..2da3675569ace8 100644
--- a/llvm/lib/Transforms/Utils/LoopUtils.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUtils.cpp
@@ -31,6 +31,7 @@
 #include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
 #include "llvm/Analysis/ScalarEvolutionExpressions.h"
 #include "llvm/IR/DIBuilder.h"
+#include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/IntrinsicInst.h"
@@ -1619,6 +1620,31 @@ int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
   // The insertion point instruction may have been deleted; clear it out
   // so that the rewriter doesn't trip over it later.
   Rewriter.clearInsertPoint();
+
+  // The loop exit values have been updated; insert the debug location
+  // for the induction variable with its final value.
+  if (PHINode *IndVar = L->getInductionVariable(*SE)) {
+    const SCEV *IndVarSCEV = SE->getSCEVAtScope(IndVar, L->getParentLoop());
+    if (isa<SCEVConstant>(IndVarSCEV)) {
+      Value *FinalIVValue = cast<SCEVConstant>(IndVarSCEV)->getValue();
+      SmallVector<DbgVariableIntrinsic *> DbgUsers;
+      SmallVector<DbgVariableIntrinsic *> DbgUsersCloned;
+      findDbgUsers(DbgUsers, IndVar);
+      for (auto &DebugUser : DbgUsers) {
+        auto *Cloned = cast<DbgVariableIntrinsic>(DebugUser->clone());
+        Cloned->replaceVariableLocationOp(static_cast<unsigned>(0),
+                                          FinalIVValue);
+        DbgUsersCloned.push_back(Cloned);
+      }
+
+      SmallVector<BasicBlock *> ExitBlocks;
+      L->getExitBlocks(ExitBlocks);
+      for (BasicBlock *Exit : ExitBlocks)
+        for (auto &DebugUser : DbgUsersCloned)
+          DebugUser->insertBefore(Exit->getFirstNonPHI());
+    }
+  }
+
   return NumReplaced;
 }
 
diff --git a/llvm/test/Transforms/LoopSimplify/pr51735-1.ll b/llvm/test/Transforms/LoopSimplify/pr51735-1.ll
index de9a7452209565..cb3e8fa43e3ecf 100644
--- a/llvm/test/Transforms/LoopSimplify/pr51735-1.ll
+++ b/llvm/test/Transforms/LoopSimplify/pr51735-1.ll
@@ -22,22 +22,12 @@
 ; 16	}
 
 ; CHECK: for.cond: {{.*}}
-; CHECK:   call void @llvm.dbg.value(metadata i32 poison, metadata ![[DBG:[0-9]+]], {{.*}}
-; CHECK:   call void @llvm.dbg.value(metadata i32 poison, metadata ![[DBG:[0-9]+]], {{.*}}
-; CHECK:   br i1 false, label %for.cond, label %for.end, {{.*}}
+; CHECK:   call void @llvm.dbg.value(metadata i32 %Index.{{[0-9]+}}, metadata ![[DBG:[0-9]+]], {{.*}}
+; CHECK:   call void @llvm.dbg.value(metadata i32 %inc, metadata ![[DBG:[0-9]+]], {{.*}}
 ; CHECK: for.end: {{.*}}
 ; CHECK:   call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG:[0-9]+]], {{.*}}
-; CHECK:   %call = tail call noundef i32 @_Z3nopi(i32 noundef 777), {{.*}}
 ; CHECK-DAG: ![[DBG]] = !DILocalVariable(name: "Index"{{.*}})
 
-define dso_local noundef i32 @_Z3nopi(i32 noundef %Param) local_unnamed_addr #0 !dbg !10 {
-entry:
-  %Param.addr = alloca i32, align 4
-  store i32 %Param, ptr %Param.addr, align 4
-  call void @llvm.dbg.declare(metadata ptr %Param.addr, metadata !15, metadata !DIExpression()), !dbg !16
-  ret i32 0, !dbg !17
-}
-
 define dso_local void @_Z3barv() local_unnamed_addr #2 !dbg !18 {
 entry:
   call void @llvm.dbg.value(metadata i32 777, metadata !21, metadata !DIExpression()), !dbg !22
@@ -55,24 +45,16 @@ for.cond:                                         ; preds = %for.cond, %entry
 
 for.end:                                          ; preds = %for.cond
   %Index.0.lcssa = phi i32 [ %Index.0, %for.cond ], !dbg !22
-  %call = tail call noundef i32 @_Z3nopi(i32 noundef %Index.0.lcssa), !dbg !34
   ret void, !dbg !35
 }
 
-define dso_local noundef i32 @main() local_unnamed_addr #3 !dbg !36 {
-entry:
-  call void @_Z3barv(), !dbg !39
-  ret i32 0, !dbg !40
-}
-
 declare void @llvm.dbg.value(metadata, metadata, metadata)
-declare void @llvm.dbg.declare(metadata, metadata, metadata)
 
 !llvm.dbg.cu = !{!0}
 !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
 !llvm.ident = !{!9}
 
-!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 18.0.0 (https://github.com/llvm/llvm-project.git 18c2eb2bf02bd7666523aa566e45d62053b7db80)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", 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}
@@ -82,14 +64,9 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata)
 !7 = !{i32 7, !"uwtable", i32 2}
 !8 = !{i32 7, !"frame-pointer", i32 2}
 !9 = !{!"clang version 18.0.0"}
-!10 = distinct !DISubprogram(name: "nop", linkageName: "_Z3nopi", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14)
-!11 = !DISubroutineType(types: !12)
 !12 = !{!13, !13}
 !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
 !14 = !{}
-!15 = !DILocalVariable(name: "Param", arg: 1, scope: !10, file: !1, line: 1, type: !13)
-!16 = !DILocation(line: 1, column: 38, scope: !10)
-!17 = !DILocation(line: 2, column: 3, scope: !10)
 !18 = distinct !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 5, type: !19, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14)
 !19 = !DISubroutineType(types: !20)
 !20 = !{null}
@@ -108,8 +85,3 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata)
 !33 = !{!"llvm.loop.mustprogress"}
 !34 = !DILocation(line: 11, column: 3, scope: !18)
 !35 = !DILocation(line: 12, column: 1, scope: !18)
-!36 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 14, type: !37, scopeLine: 14, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
-!37 = !DISubroutineType(types: !38)
-!38 = !{!13}
-!39 = !DILocation(line: 15, column: 3, scope: !36)
-!40 = !DILocation(line: 16, column: 1, scope: !36)
diff --git a/llvm/test/Transforms/LoopSimplify/pr51735.ll b/llvm/test/Transforms/LoopSimplify/pr51735.ll
index b9bdc8ca1b6fb0..c86f8ed7d0274f 100644
--- a/llvm/test/Transforms/LoopSimplify/pr51735.ll
+++ b/llvm/test/Transforms/LoopSimplify/pr51735.ll
@@ -27,14 +27,8 @@
 ; CHECK:   br i1 false, label %for.cond, label %for.end, {{.*}}
 ; CHECK: for.end: {{.*}}
 ; CHECK:   call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG:[0-9]+]], {{.*}}
-; CHECK:   %call = tail call noundef i32 @_Z3nopv(), {{.*}}
 ; CHECK-DAG: ![[DBG]] = !DILocalVariable(name: "Index"{{.*}})
 
-define dso_local noundef i32 @_Z3nopv() local_unnamed_addr #0 !dbg !10 {
-entry:
-  ret i32 0, !dbg !14
-}
-
 define dso_local void @_Z3barv() local_unnamed_addr #1 !dbg !15 {
 entry:
   call void @llvm.dbg.value(metadata i32 777, metadata !19, metadata !DIExpression()), !dbg !20
@@ -51,23 +45,16 @@ for.cond:                                         ; preds = %for.cond, %entry
   br i1 %cmp, label %for.cond, label %for.end, !dbg !28, !llvm.loop !29
 
 for.end:                                          ; preds = %for.cond
-  %call = tail call noundef i32 @_Z3nopv(), !dbg !32
   ret void, !dbg !33
 }
 
-define dso_local noundef i32 @main() local_unnamed_addr #2 !dbg !34 {
-entry:
-  call void @_Z3barv(), !dbg !35
-  ret i32 0, !dbg !36
-}
-
 declare void @llvm.dbg.value(metadata, metadata, metadata)
 
 !llvm.dbg.cu = !{!0}
 !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
 !llvm.ident = !{!9}
 
-!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 18.0.0 (https://github.com/llvm/llvm-project.git 18c2eb2bf02bd7666523aa566e45d62053b7db80)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", 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}
@@ -77,11 +64,7 @@ declare void @llvm.dbg.value(metadata, metadata, metadata)
 !7 = !{i32 7, !"uwtable", i32 2}
 !8 = !{i32 7, !"frame-pointer", i32 2}
 !9 = !{!"clang version 18.0.0"}
-!10 = distinct !DISubprogram(name: "nop", linkageName: "_Z3nopv", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
-!11 = !DISubroutineType(types: !12)
-!12 = !{!13}
 !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
-!14 = !DILocation(line: 2, column: 3, scope: !10)
 !15 = distinct !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 5, type: !16, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !18)
 !16 = !DISubroutineType(types: !17)
 !17 = !{null}
@@ -99,8 +82,4 @@ declare void @llvm.dbg.value(metadata, metadata, metadata)
 !29 = distinct !{!29, !28, !30, !31}
 !30 = !DILocation(line: 10, column: 5, scope: !26)
 !31 = !{!"llvm.loop.mustprogress"}
-!32 = !DILocation(line: 11, column: 3, scope: !15)
 !33 = !DILocation(line: 12, column: 1, scope: !15)
-!34 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 14, type: !11, scopeLine: 14, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
-!35 = !DILocation(line: 15, column: 3, scope: !34)
-!36 = !DILocation(line: 16, column: 1, scope: !34)

>From a27cef06b5201790099b26cdf6f18b2faa1e4431 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <carlos.alberto.enciso at gmail.com>
Date: Fri, 8 Dec 2023 14:14:29 +0000
Subject: [PATCH 03/11] [indvars] Missing variables at Og:

https://bugs.llvm.org/show_bug.cgi?id=51735
https://github.com/llvm/llvm-project/issues/51077

In the given test case:

 4 ...
 5 void bar() {
 6   int End = 777;
 7   int Index = 27;
 8   char Var = 1;
 9   for (; Index < End; ++Index)
10     ;
11   nop();
12 }
13 ...

Missing local variable 'Index' after loop 'Induction Variable Elimination'.
When adding a breakpoint at line 11, LLDB does not have information on
the variable. But it has info on 'Var' and 'End'.

Address reviewers comments.
- Early exit to simplify the logic.
- Avoid inserting the same instruction in multiple blocks.
- Skip debug-users with variadic variable locations.
- Change some comments to improve readability.
- Add code to clone and move the debug value.
- Modify second test case to include multiple exit blocks.
---
 .../include/llvm/Transforms/Utils/LoopUtils.h |   4 +
 llvm/lib/Transforms/Scalar/IndVarSimplify.cpp |   1 -
 llvm/lib/Transforms/Utils/LoopUtils.cpp       |  81 ++++++---
 .../test/Transforms/LoopSimplify/pr51735-1.ll | 155 +++++++++++-------
 llvm/test/Transforms/LoopSimplify/pr51735.ll  |  13 +-
 5 files changed, 159 insertions(+), 95 deletions(-)

diff --git a/llvm/include/llvm/Transforms/Utils/LoopUtils.h b/llvm/include/llvm/Transforms/Utils/LoopUtils.h
index 187ace3a0cbedf..7ec2c36e2913ae 100644
--- a/llvm/include/llvm/Transforms/Utils/LoopUtils.h
+++ b/llvm/include/llvm/Transforms/Utils/LoopUtils.h
@@ -477,6 +477,10 @@ int rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
                           ReplaceExitVal ReplaceExitValue,
                           SmallVector<WeakTrackingVH, 16> &DeadInsts);
 
+/// Assign exit values to variables that use this loop variable during the loop.
+void addDebugValuesToLoopVariable(Loop *L, ScalarEvolution *SE, PHINode *PN);
+void addDebugValuesToLoopVariable(Loop *L, Value *ExitValue, PHINode *PN);
+
 /// Set weights for \p UnrolledLoop and \p RemainderLoop based on weights for
 /// \p OrigLoop and the following distribution of \p OrigLoop iteration among \p
 /// UnrolledLoop and \p RemainderLoop. \p UnrolledLoop receives weights that
diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
index 2a6997c48883d4..41c4d623617347 100644
--- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
+++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
@@ -46,7 +46,6 @@
 #include "llvm/IR/ConstantRange.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
-#include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/Function.h"
diff --git a/llvm/lib/Transforms/Utils/LoopUtils.cpp b/llvm/lib/Transforms/Utils/LoopUtils.cpp
index 2da3675569ace8..b84a9263d18284 100644
--- a/llvm/lib/Transforms/Utils/LoopUtils.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUtils.cpp
@@ -1413,6 +1413,36 @@ static bool checkIsIndPhi(PHINode *Phi, Loop *L, ScalarEvolution *SE,
   return InductionDescriptor::isInductionPHI(Phi, L, SE, ID);
 }
 
+void llvm::addDebugValuesToLoopVariable(Loop *L, Value *ExitValue,
+                                        PHINode *PN) {
+  SmallVector<BasicBlock *> ExitBlocks;
+  L->getExitBlocks(ExitBlocks);
+  SmallVector<DbgVariableIntrinsic *> DbgUsers;
+  findDbgUsers(DbgUsers, PN);
+  for (auto *DebugUser : DbgUsers) {
+    // Skip debug-users with variadic variable locations; they will not,
+    // get updated, which is fine as that is the existing behaviour.
+    if (DebugUser->hasArgList())
+      continue;
+    for (BasicBlock *Exit : ExitBlocks) {
+      auto *Cloned = cast<DbgVariableIntrinsic>(DebugUser->clone());
+      Cloned->replaceVariableLocationOp(0u, ExitValue);
+      Cloned->insertBefore(Exit->getFirstNonPHI());
+    }
+  }
+}
+
+void llvm::addDebugValuesToLoopVariable(Loop *L, ScalarEvolution *SE,
+                                        PHINode *PN) {
+  if (!PN)
+    return;
+  const SCEV *PNSCEV = SE->getSCEVAtScope(PN, L->getParentLoop());
+  if (auto *Const = dyn_cast<SCEVConstant>(PNSCEV)) {
+    Value *FinalIVValue = Const->getValue();
+    addDebugValuesToLoopVariable(L, FinalIVValue, PN);
+  }
+}
+
 int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
                                 ScalarEvolution *SE,
                                 const TargetTransformInfo *TTI,
@@ -1554,6 +1584,21 @@ int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
           (isa<PHINode>(Inst) || isa<LandingPadInst>(Inst)) ?
           &*Inst->getParent()->getFirstInsertionPt() : Inst;
         RewritePhiSet.emplace_back(PN, i, ExitValue, InsertPt, HighCost);
+
+        // Add debug values if the PN is a induction variable.
+        PHINode *IndVar = L->getInductionVariable(*SE);
+        for (Value *V : PN->incoming_values())
+          if (V == IndVar) {
+            if (BasicBlock *Successor = ExitBB->getSingleSuccessor()) {
+              SmallVector<DbgVariableIntrinsic *> DbgUsers;
+              findDbgUsers(DbgUsers, V);
+              for (auto *DebugUser : DbgUsers) {
+                auto *Cloned = cast<DbgVariableIntrinsic>(DebugUser->clone());
+                Cloned->replaceVariableLocationOp(0u, PN);
+                Cloned->insertBefore(Successor->getFirstNonPHI());
+              }
+            }
+          }
       }
     }
   }
@@ -1612,39 +1657,25 @@ int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
     // Replace PN with ExitVal if that is legal and does not break LCSSA.
     if (PN->getNumIncomingValues() == 1 &&
         LI->replacementPreservesLCSSAForm(PN, ExitVal)) {
+      addDebugValuesToLoopVariable(L, ExitVal, PN);
       PN->replaceAllUsesWith(ExitVal);
       PN->eraseFromParent();
     }
   }
 
+  // If there are no PHIs to be rewritten then there are no loop live-out
+  // values, try to rewrite variables corresponding to the induction variable
+  // with their constant exit-values if we computed any. Otherwise debug-info
+  // will completely forget that this loop happened.
+  if (RewritePhiSet.empty()) {
+    // The loop exit value has been updated; insert the debug location
+    // for the given the induction variable with its final value.
+    addDebugValuesToLoopVariable(L, SE, L->getInductionVariable(*SE));
+  }
+
   // The insertion point instruction may have been deleted; clear it out
   // so that the rewriter doesn't trip over it later.
   Rewriter.clearInsertPoint();
-
-  // The loop exit values have been updated; insert the debug location
-  // for the induction variable with its final value.
-  if (PHINode *IndVar = L->getInductionVariable(*SE)) {
-    const SCEV *IndVarSCEV = SE->getSCEVAtScope(IndVar, L->getParentLoop());
-    if (isa<SCEVConstant>(IndVarSCEV)) {
-      Value *FinalIVValue = cast<SCEVConstant>(IndVarSCEV)->getValue();
-      SmallVector<DbgVariableIntrinsic *> DbgUsers;
-      SmallVector<DbgVariableIntrinsic *> DbgUsersCloned;
-      findDbgUsers(DbgUsers, IndVar);
-      for (auto &DebugUser : DbgUsers) {
-        auto *Cloned = cast<DbgVariableIntrinsic>(DebugUser->clone());
-        Cloned->replaceVariableLocationOp(static_cast<unsigned>(0),
-                                          FinalIVValue);
-        DbgUsersCloned.push_back(Cloned);
-      }
-
-      SmallVector<BasicBlock *> ExitBlocks;
-      L->getExitBlocks(ExitBlocks);
-      for (BasicBlock *Exit : ExitBlocks)
-        for (auto &DebugUser : DbgUsersCloned)
-          DebugUser->insertBefore(Exit->getFirstNonPHI());
-    }
-  }
-
   return NumReplaced;
 }
 
diff --git a/llvm/test/Transforms/LoopSimplify/pr51735-1.ll b/llvm/test/Transforms/LoopSimplify/pr51735-1.ll
index cb3e8fa43e3ecf..293553b000c13c 100644
--- a/llvm/test/Transforms/LoopSimplify/pr51735-1.ll
+++ b/llvm/test/Transforms/LoopSimplify/pr51735-1.ll
@@ -1,54 +1,78 @@
 ; RUN: opt -passes=indvars -S -o - < %s | FileCheck %s
 
-; Missing local variable 'Index' after loop 'Induction Variable Elimination'.
-; When adding a breakpoint at line 11, LLDB does not have information on
-; the variable. But it has info on 'Var' and 'End'.
-
-;  1	__attribute__((optnone)) int nop(int Param) {
-;  2	  return 0;
-;  3	}
-;  4
-;  5	void bar() {
-;  6    int End = 777;
-;  7	  int Index = 27;
-;  8	  char Var = 1;
-;  9	  for (; Index < End; ++Index)
-; 10	    ;
-; 11	  nop(Index);
-; 12	}
-; 13
-; 14	int main () {
-; 15	  bar();
-; 16	}
-
-; CHECK: for.cond: {{.*}}
-; CHECK:   call void @llvm.dbg.value(metadata i32 %Index.{{[0-9]+}}, metadata ![[DBG:[0-9]+]], {{.*}}
-; CHECK:   call void @llvm.dbg.value(metadata i32 %inc, metadata ![[DBG:[0-9]+]], {{.*}}
-; CHECK: for.end: {{.*}}
-; CHECK:   call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG:[0-9]+]], {{.*}}
+; Make sure that when we delete the loop, that the variable Index has
+; the 777 value.
+
+; CHECK: for.cond:
+; CHECK:   call void @llvm.dbg.value(metadata i32 %Index.0, metadata ![[DBG:[0-9]+]], {{.*}}
+
+; CHECK: for.extra:
+; CHECK:   %call.0 = call noundef i32 @"?nop@@YAHH at Z"(i32 noundef %Index.0), {{.*}}
+; CHECK:   br i1 %cmp.0, label %for.cond, label %if.else, {{.*}}
+
+; CHECK: if.then:
+; CHECK:   call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG]], {{.*}}
+; CHECK:   br label %for.end, {{.*}}
+
+; CHECK: if.else:
+; CHECK:   call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG]], {{.*}}
+; CHECK:   br label %for.end, {{.*}}
+
+; CHECK: for.end:
+; CHECK:   call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG]], {{.*}}
+
 ; CHECK-DAG: ![[DBG]] = !DILocalVariable(name: "Index"{{.*}})
 
-define dso_local void @_Z3barv() local_unnamed_addr #2 !dbg !18 {
+define dso_local noundef i32 @"?nop@@YAHH at Z"(i32 noundef %Param) !dbg !11 {
 entry:
-  call void @llvm.dbg.value(metadata i32 777, metadata !21, metadata !DIExpression()), !dbg !22
-  call void @llvm.dbg.value(metadata i32 27, metadata !23, metadata !DIExpression()), !dbg !22
-  call void @llvm.dbg.value(metadata i32 1, metadata !24, metadata !DIExpression()), !dbg !22
-  br label %for.cond, !dbg !25
+  %Param.addr = alloca i32, align 4
+  store i32 %Param, ptr %Param.addr, align 4
+  call void @llvm.dbg.declare(metadata ptr %Param.addr, metadata !32, metadata !DIExpression()), !dbg !35
+  ret i32 0, !dbg !36
+}
+
+define dso_local void @_Z3barv() local_unnamed_addr #1 !dbg !12 {
+entry:
+  call void @llvm.dbg.value(metadata i32 777, metadata !16, metadata !DIExpression()), !dbg !17
+  call void @llvm.dbg.value(metadata i32 27, metadata !18, metadata !DIExpression()), !dbg !17
+  call void @llvm.dbg.value(metadata i32 1, metadata !19, metadata !DIExpression()), !dbg !17
+  call void @llvm.dbg.value(metadata i32 1, metadata !30, metadata !DIExpression()), !dbg !17
+  br label %for.cond, !dbg !20
 
 for.cond:                                         ; preds = %for.cond, %entry
-  %Index.0 = phi i32 [ 27, %entry ], [ %inc, %for.cond ], !dbg !22
-  call void @llvm.dbg.value(metadata i32 %Index.0, metadata !23, metadata !DIExpression()), !dbg !22
-  %cmp = icmp ult i32 %Index.0, 777, !dbg !26
-  %inc = add nuw nsw i32 %Index.0, 1, !dbg !29
-  call void @llvm.dbg.value(metadata i32 %inc, metadata !23, metadata !DIExpression()), !dbg !22
-  br i1 %cmp, label %for.cond, label %for.end, !dbg !30, !llvm.loop !31
-
-for.end:                                          ; preds = %for.cond
-  %Index.0.lcssa = phi i32 [ %Index.0, %for.cond ], !dbg !22
-  ret void, !dbg !35
+  %Index.0 = phi i32 [ 27, %entry ], [ %inc, %for.extra ], !dbg !17
+  call void @llvm.dbg.value(metadata i32 %Index.0, metadata !18, metadata !DIExpression()), !dbg !17
+  %cmp = icmp ult i32 %Index.0, 777, !dbg !21
+  %inc = add nuw nsw i32 %Index.0, 1, !dbg !24
+  call void @llvm.dbg.value(metadata i32 %inc, metadata !18, metadata !DIExpression()), !dbg !17
+  br i1 %cmp, label %for.extra, label %if.then, !dbg !25, !llvm.loop !26
+
+for.extra:
+  %call.0 = call noundef i32 @"?nop@@YAHH at Z"(i32 noundef %Index.0), !dbg !21
+  %cmp.0 = icmp ult i32 %Index.0, %call.0, !dbg !21
+  br i1 %cmp.0, label %for.cond, label %if.else, !dbg !25, !llvm.loop !26
+
+if.then:                                          ; preds = %for.cond
+  %Var.1 = add nsw i32 %Index.0, 1, !dbg !20
+  call void @llvm.dbg.value(metadata i32 %Var.1, metadata !19, metadata !DIExpression()), !dbg !20
+  br label %for.end, !dbg !20
+
+if.else:
+  %Var.2 = add nsw i32 %Index.0, 2, !dbg !20
+  call void @llvm.dbg.value(metadata i32 %Var.2, metadata !19, metadata !DIExpression()), !dbg !20
+  br label %for.end, !dbg !20
+
+for.end:                                          ; preds = %if.else, %if.then
+  %Zeta.0 = phi i32 [ %Var.1, %if.then ], [ %Var.2, %if.else ], !dbg !20
+  call void @llvm.dbg.value(metadata i32 %Zeta.0, metadata !30, metadata !DIExpression()), !dbg !20
+  %Var.3 = add nsw i32 %Index.0, 1, !dbg !20
+  call void @llvm.dbg.value(metadata i32 %Var.3, metadata !19, metadata !DIExpression()), !dbg !20
+  %call = call noundef i32 @"?nop@@YAHH at Z"(i32 noundef %Index.0), !dbg !37
+  ret void, !dbg !29
 }
 
 declare void @llvm.dbg.value(metadata, metadata, metadata)
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
 
 !llvm.dbg.cu = !{!0}
 !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
@@ -64,24 +88,31 @@ declare void @llvm.dbg.value(metadata, metadata, metadata)
 !7 = !{i32 7, !"uwtable", i32 2}
 !8 = !{i32 7, !"frame-pointer", i32 2}
 !9 = !{!"clang version 18.0.0"}
-!12 = !{!13, !13}
-!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
-!14 = !{}
-!18 = distinct !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 5, type: !19, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14)
-!19 = !DISubroutineType(types: !20)
-!20 = !{null}
-!21 = !DILocalVariable(name: "End", scope: !18, file: !1, line: 6, type: !13)
-!22 = !DILocation(line: 0, scope: !18)
-!23 = !DILocalVariable(name: "Index", scope: !18, file: !1, line: 7, type: !13)
-!24 = !DILocalVariable(name: "Var", scope: !18, file: !1, line: 8, type: !13)
-!25 = !DILocation(line: 9, column: 3, scope: !18)
-!26 = !DILocation(line: 9, column: 16, scope: !27)
-!27 = distinct !DILexicalBlock(scope: !28, file: !1, line: 9, column: 3)
-!28 = distinct !DILexicalBlock(scope: !18, file: !1, line: 9, column: 3)
-!29 = !DILocation(line: 9, column: 23, scope: !27)
-!30 = !DILocation(line: 9, column: 3, scope: !28)
-!31 = distinct !{!31, !30, !32, !33}
-!32 = !DILocation(line: 10, column: 5, scope: !28)
-!33 = !{!"llvm.loop.mustprogress"}
-!34 = !DILocation(line: 11, column: 3, scope: !18)
-!35 = !DILocation(line: 12, column: 1, scope: !18)
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = distinct !DISubprogram(name: "nop", linkageName: "?nop@@YAHH at Z", scope: !1, file: !1, line: 1, type: !33, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !31)
+!12 = distinct !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 5, type: !13, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !15)
+!13 = !DISubroutineType(types: !14)
+!14 = !{null}
+!15 = !{}
+!16 = !DILocalVariable(name: "End", scope: !12, file: !1, line: 6, type: !10)
+!17 = !DILocation(line: 0, scope: !12)
+!18 = !DILocalVariable(name: "Index", scope: !12, file: !1, line: 7, type: !10)
+!19 = !DILocalVariable(name: "Var", scope: !12, file: !1, line: 8, type: !10)
+!20 = !DILocation(line: 9, column: 3, scope: !12)
+!21 = !DILocation(line: 9, column: 16, scope: !22)
+!22 = distinct !DILexicalBlock(scope: !23, file: !1, line: 9, column: 3)
+!23 = distinct !DILexicalBlock(scope: !12, file: !1, line: 9, column: 3)
+!24 = !DILocation(line: 9, column: 23, scope: !22)
+!25 = !DILocation(line: 9, column: 3, scope: !23)
+!26 = distinct !{!26, !25, !27, !28}
+!27 = !DILocation(line: 10, column: 5, scope: !23)
+!28 = !{!"llvm.loop.mustprogress"}
+!29 = !DILocation(line: 12, column: 1, scope: !12)
+!30 = !DILocalVariable(name: "Zeta", scope: !12, file: !1, line: 8, type: !10)
+!31 = !{!32}
+!32 = !DILocalVariable(name: "Param", arg: 1, scope: !11, file: !1, line: 1, type: !10)
+!33 = !DISubroutineType(types: !34)
+!34 = !{!10, !10}
+!35 = !DILocation(line: 1, scope: !11)
+!36 = !DILocation(line: 2, scope: !11)
+!37 = !DILocation(line: 20, scope: !12)
diff --git a/llvm/test/Transforms/LoopSimplify/pr51735.ll b/llvm/test/Transforms/LoopSimplify/pr51735.ll
index c86f8ed7d0274f..5eb8bb50f33359 100644
--- a/llvm/test/Transforms/LoopSimplify/pr51735.ll
+++ b/llvm/test/Transforms/LoopSimplify/pr51735.ll
@@ -1,8 +1,7 @@
 ; RUN: opt -passes=indvars -S -o - < %s | FileCheck %s
 
-; Missing local variable 'Index' after loop 'Induction Variable Elimination'.
-; When adding a breakpoint at line 11, LLDB does not have information on
-; the variable. But it has info on 'Var' and 'End'.
+; Make sure that when we delete the loop in the code below, that the variable
+; Index has the 777 value.
 
 ;  1	__attribute__((optnone)) int nop() {
 ;  2	  return 0;
@@ -21,12 +20,12 @@
 ; 15	  bar();
 ; 16	}
 
-; CHECK: for.cond: {{.*}}
-; CHECK:   call void @llvm.dbg.value(metadata i32 poison, metadata ![[DBG:[0-9]+]], {{.*}}
+; CHECK: for.cond:
 ; CHECK:   call void @llvm.dbg.value(metadata i32 poison, metadata ![[DBG:[0-9]+]], {{.*}}
+; CHECK:   call void @llvm.dbg.value(metadata i32 poison, metadata ![[DBG]], {{.*}}
 ; CHECK:   br i1 false, label %for.cond, label %for.end, {{.*}}
-; CHECK: for.end: {{.*}}
-; CHECK:   call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG:[0-9]+]], {{.*}}
+; CHECK: for.end:
+; CHECK:   call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG]], {{.*}}
 ; CHECK-DAG: ![[DBG]] = !DILocalVariable(name: "Index"{{.*}})
 
 define dso_local void @_Z3barv() local_unnamed_addr #1 !dbg !15 {

>From 5935de96d37dacb38dd2e105819c16d08e278fba Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <carlos.alberto.enciso at gmail.com>
Date: Tue, 9 Jan 2024 13:16:01 +0000
Subject: [PATCH 04/11] [indvars] Missing variables at Og:

https://bugs.llvm.org/show_bug.cgi?id=51735
https://github.com/llvm/llvm-project/issues/51077

In the given test case:

 4 ...
 5 void bar() {
 6   int End = 777;
 7   int Index = 27;
 8   char Var = 1;
 9   for (; Index < End; ++Index)
10     ;
11   nop();
12 }
13 ...

Missing local variable 'Index' after loop 'Induction Variable Elimination'.
When adding a breakpoint at line 11, LLDB does not have information on
the variable. But it has info on 'Var' and 'End'.

Address reviewers comments.
- Early exit to simplify the logic.
- Avoid inserting the same instruction in multiple blocks.
- Skip debug-users with variadic variable locations.
- Change some comments to improve readability.
- Add code to clone and move the debug value.
- Modify second test case to include multiple exit blocks.

Addressed the upstream feedback in relation to:
- Each exit block has its own exit value.
- Separate the debug values for incoming and exit values.
---
 .../include/llvm/Transforms/Utils/LoopUtils.h |  5 +-
 llvm/lib/Transforms/Utils/LoopUtils.cpp       | 52 ++++++++++---------
 .../test/Transforms/LoopSimplify/pr51735-1.ll |  4 +-
 3 files changed, 34 insertions(+), 27 deletions(-)

diff --git a/llvm/include/llvm/Transforms/Utils/LoopUtils.h b/llvm/include/llvm/Transforms/Utils/LoopUtils.h
index 7ec2c36e2913ae..cb4c92f7318374 100644
--- a/llvm/include/llvm/Transforms/Utils/LoopUtils.h
+++ b/llvm/include/llvm/Transforms/Utils/LoopUtils.h
@@ -478,8 +478,11 @@ int rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
                           SmallVector<WeakTrackingVH, 16> &DeadInsts);
 
 /// Assign exit values to variables that use this loop variable during the loop.
+void addDebugValuesToIncomingValue(BasicBlock *Successor, Value *IndVar,
+                                   PHINode *PN);
+void addDebugValuesToLoopVariable(BasicBlock *Successor, Value *ExitValue,
+                                  PHINode *PN);
 void addDebugValuesToLoopVariable(Loop *L, ScalarEvolution *SE, PHINode *PN);
-void addDebugValuesToLoopVariable(Loop *L, Value *ExitValue, PHINode *PN);
 
 /// Set weights for \p UnrolledLoop and \p RemainderLoop based on weights for
 /// \p OrigLoop and the following distribution of \p OrigLoop iteration among \p
diff --git a/llvm/lib/Transforms/Utils/LoopUtils.cpp b/llvm/lib/Transforms/Utils/LoopUtils.cpp
index b84a9263d18284..b0426bf216d8ce 100644
--- a/llvm/lib/Transforms/Utils/LoopUtils.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUtils.cpp
@@ -1338,11 +1338,12 @@ struct RewritePhi {
   const SCEV *ExpansionSCEV; // The SCEV of the incoming value we are rewriting.
   Instruction *ExpansionPoint; // Where we'd like to expand that SCEV?
   bool HighCost;               // Is this expansion a high-cost?
+  BasicBlock *ExitBlock;       // Exit block for PHI node.
 
   RewritePhi(PHINode *P, unsigned I, const SCEV *Val, Instruction *ExpansionPt,
-             bool H)
+             bool H, BasicBlock *Exit)
       : PN(P), Ith(I), ExpansionSCEV(Val), ExpansionPoint(ExpansionPt),
-        HighCost(H) {}
+        HighCost(H), ExitBlock(Exit) {}
 };
 
 // Check whether it is possible to delete the loop after rewriting exit
@@ -1413,10 +1414,19 @@ static bool checkIsIndPhi(PHINode *Phi, Loop *L, ScalarEvolution *SE,
   return InductionDescriptor::isInductionPHI(Phi, L, SE, ID);
 }
 
-void llvm::addDebugValuesToLoopVariable(Loop *L, Value *ExitValue,
+void llvm::addDebugValuesToIncomingValue(BasicBlock *Successor, Value *IndVar,
+                                         PHINode *PN) {
+  SmallVector<DbgVariableIntrinsic *> DbgUsers;
+  findDbgUsers(DbgUsers, IndVar);
+  for (auto *DebugUser : DbgUsers) {
+    auto *Cloned = cast<DbgVariableIntrinsic>(DebugUser->clone());
+    Cloned->replaceVariableLocationOp(0u, PN);
+    Cloned->insertBefore(Successor->getFirstNonPHI());
+  }
+}
+
+void llvm::addDebugValuesToLoopVariable(BasicBlock *Successor, Value *ExitValue,
                                         PHINode *PN) {
-  SmallVector<BasicBlock *> ExitBlocks;
-  L->getExitBlocks(ExitBlocks);
   SmallVector<DbgVariableIntrinsic *> DbgUsers;
   findDbgUsers(DbgUsers, PN);
   for (auto *DebugUser : DbgUsers) {
@@ -1424,11 +1434,9 @@ void llvm::addDebugValuesToLoopVariable(Loop *L, Value *ExitValue,
     // get updated, which is fine as that is the existing behaviour.
     if (DebugUser->hasArgList())
       continue;
-    for (BasicBlock *Exit : ExitBlocks) {
-      auto *Cloned = cast<DbgVariableIntrinsic>(DebugUser->clone());
-      Cloned->replaceVariableLocationOp(0u, ExitValue);
-      Cloned->insertBefore(Exit->getFirstNonPHI());
-    }
+    auto *Cloned = cast<DbgVariableIntrinsic>(DebugUser->clone());
+    Cloned->replaceVariableLocationOp(0u, ExitValue);
+    Cloned->insertBefore(Successor->getFirstNonPHI());
   }
 }
 
@@ -1439,7 +1447,10 @@ void llvm::addDebugValuesToLoopVariable(Loop *L, ScalarEvolution *SE,
   const SCEV *PNSCEV = SE->getSCEVAtScope(PN, L->getParentLoop());
   if (auto *Const = dyn_cast<SCEVConstant>(PNSCEV)) {
     Value *FinalIVValue = Const->getValue();
-    addDebugValuesToLoopVariable(L, FinalIVValue, PN);
+    SmallVector<BasicBlock *> ExitBlocks;
+    L->getExitBlocks(ExitBlocks);
+    for (BasicBlock *Exit : ExitBlocks)
+      addDebugValuesToLoopVariable(Exit, FinalIVValue, PN);
   }
 }
 
@@ -1583,22 +1594,13 @@ int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
         Instruction *InsertPt =
           (isa<PHINode>(Inst) || isa<LandingPadInst>(Inst)) ?
           &*Inst->getParent()->getFirstInsertionPt() : Inst;
-        RewritePhiSet.emplace_back(PN, i, ExitValue, InsertPt, HighCost);
+        RewritePhiSet.emplace_back(PN, i, ExitValue, InsertPt, HighCost, ExitBB);
 
         // Add debug values if the PN is a induction variable.
         PHINode *IndVar = L->getInductionVariable(*SE);
-        for (Value *V : PN->incoming_values())
-          if (V == IndVar) {
-            if (BasicBlock *Successor = ExitBB->getSingleSuccessor()) {
-              SmallVector<DbgVariableIntrinsic *> DbgUsers;
-              findDbgUsers(DbgUsers, V);
-              for (auto *DebugUser : DbgUsers) {
-                auto *Cloned = cast<DbgVariableIntrinsic>(DebugUser->clone());
-                Cloned->replaceVariableLocationOp(0u, PN);
-                Cloned->insertBefore(Successor->getFirstNonPHI());
-              }
-            }
-          }
+        if (PN->getIncomingValue(i) == IndVar)
+          if (BasicBlock *Successor = ExitBB->getSingleSuccessor())
+            addDebugValuesToIncomingValue(Successor, PN->getIncomingValue(i), PN);
       }
     }
   }
@@ -1657,7 +1659,7 @@ int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
     // Replace PN with ExitVal if that is legal and does not break LCSSA.
     if (PN->getNumIncomingValues() == 1 &&
         LI->replacementPreservesLCSSAForm(PN, ExitVal)) {
-      addDebugValuesToLoopVariable(L, ExitVal, PN);
+      addDebugValuesToLoopVariable(Phi.ExitBlock, ExitVal, PN);
       PN->replaceAllUsesWith(ExitVal);
       PN->eraseFromParent();
     }
diff --git a/llvm/test/Transforms/LoopSimplify/pr51735-1.ll b/llvm/test/Transforms/LoopSimplify/pr51735-1.ll
index 293553b000c13c..20cadcac47b60f 100644
--- a/llvm/test/Transforms/LoopSimplify/pr51735-1.ll
+++ b/llvm/test/Transforms/LoopSimplify/pr51735-1.ll
@@ -12,16 +12,18 @@
 
 ; CHECK: if.then:
 ; CHECK:   call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG]], {{.*}}
+; CHECK:   call void @llvm.dbg.value(metadata i32 %Var.1, metadata ![[VAR:[0-9]+]], {{.*}}
 ; CHECK:   br label %for.end, {{.*}}
 
 ; CHECK: if.else:
-; CHECK:   call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG]], {{.*}}
+; CHECK:   call void @llvm.dbg.value(metadata i32 %Var.2, metadata ![[VAR:[0-9]+]], {{.*}}
 ; CHECK:   br label %for.end, {{.*}}
 
 ; CHECK: for.end:
 ; CHECK:   call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG]], {{.*}}
 
 ; CHECK-DAG: ![[DBG]] = !DILocalVariable(name: "Index"{{.*}})
+; CHECK-DAG: ![[VAR]] = !DILocalVariable(name: "Var"{{.*}})
 
 define dso_local noundef i32 @"?nop@@YAHH at Z"(i32 noundef %Param) !dbg !11 {
 entry:

>From 9941c3a2a85c939929274e7ca70c3a88b5aaf6c8 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <carlos.alberto.enciso at gmail.com>
Date: Tue, 9 Jan 2024 14:44:10 +0000
Subject: [PATCH 05/11] [indvars] Missing variables at Og:

https://bugs.llvm.org/show_bug.cgi?id=51735
https://github.com/llvm/llvm-project/issues/51077

Fix clang-format found issues in updated patch.
---
 llvm/lib/Transforms/Utils/LoopUtils.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/LoopUtils.cpp b/llvm/lib/Transforms/Utils/LoopUtils.cpp
index b0426bf216d8ce..6057cda2e679e0 100644
--- a/llvm/lib/Transforms/Utils/LoopUtils.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUtils.cpp
@@ -1594,13 +1594,15 @@ int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
         Instruction *InsertPt =
           (isa<PHINode>(Inst) || isa<LandingPadInst>(Inst)) ?
           &*Inst->getParent()->getFirstInsertionPt() : Inst;
-        RewritePhiSet.emplace_back(PN, i, ExitValue, InsertPt, HighCost, ExitBB);
+        RewritePhiSet.emplace_back(PN, i, ExitValue, InsertPt, HighCost,
+                                   ExitBB);
 
         // Add debug values if the PN is a induction variable.
         PHINode *IndVar = L->getInductionVariable(*SE);
         if (PN->getIncomingValue(i) == IndVar)
           if (BasicBlock *Successor = ExitBB->getSingleSuccessor())
-            addDebugValuesToIncomingValue(Successor, PN->getIncomingValue(i), PN);
+            addDebugValuesToIncomingValue(Successor, PN->getIncomingValue(i),
+                                          PN);
       }
     }
   }

>From bf5b9bcf29bdc51123b0e8c1d82307e8aa472d42 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <carlos.alberto.enciso at gmail.com>
Date: Tue, 16 Jan 2024 12:10:46 +0000
Subject: [PATCH 06/11] [indvars] Missing variables at Og:

https://bugs.llvm.org/show_bug.cgi?id=51735
https://github.com/llvm/llvm-project/issues/51077

Addressed the upstream feedback in relation to:
- Remove the introduced 'ExitBlock' field.
- Update some comments.
---
 llvm/lib/Transforms/Utils/LoopUtils.cpp | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/LoopUtils.cpp b/llvm/lib/Transforms/Utils/LoopUtils.cpp
index 6057cda2e679e0..716075d13ef697 100644
--- a/llvm/lib/Transforms/Utils/LoopUtils.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUtils.cpp
@@ -1338,12 +1338,11 @@ struct RewritePhi {
   const SCEV *ExpansionSCEV; // The SCEV of the incoming value we are rewriting.
   Instruction *ExpansionPoint; // Where we'd like to expand that SCEV?
   bool HighCost;               // Is this expansion a high-cost?
-  BasicBlock *ExitBlock;       // Exit block for PHI node.
 
   RewritePhi(PHINode *P, unsigned I, const SCEV *Val, Instruction *ExpansionPt,
-             bool H, BasicBlock *Exit)
+             bool H)
       : PN(P), Ith(I), ExpansionSCEV(Val), ExpansionPoint(ExpansionPt),
-        HighCost(H), ExitBlock(Exit) {}
+        HighCost(H) {}
 };
 
 // Check whether it is possible to delete the loop after rewriting exit
@@ -1594,8 +1593,7 @@ int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
         Instruction *InsertPt =
           (isa<PHINode>(Inst) || isa<LandingPadInst>(Inst)) ?
           &*Inst->getParent()->getFirstInsertionPt() : Inst;
-        RewritePhiSet.emplace_back(PN, i, ExitValue, InsertPt, HighCost,
-                                   ExitBB);
+        RewritePhiSet.emplace_back(PN, i, ExitValue, InsertPt, HighCost);
 
         // Add debug values if the PN is a induction variable.
         PHINode *IndVar = L->getInductionVariable(*SE);
@@ -1661,19 +1659,19 @@ int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
     // Replace PN with ExitVal if that is legal and does not break LCSSA.
     if (PN->getNumIncomingValues() == 1 &&
         LI->replacementPreservesLCSSAForm(PN, ExitVal)) {
-      addDebugValuesToLoopVariable(Phi.ExitBlock, ExitVal, PN);
+      addDebugValuesToLoopVariable(PN->getParent(), ExitVal, PN);
       PN->replaceAllUsesWith(ExitVal);
       PN->eraseFromParent();
     }
   }
 
   // If there are no PHIs to be rewritten then there are no loop live-out
-  // values, try to rewrite variables corresponding to the induction variable
-  // with their constant exit-values if we computed any. Otherwise debug-info
-  // will completely forget that this loop happened.
+  // values, try to rewrite debug variables corresponding to the induction
+  // variable with their constant exit-values if we computed any. Otherwise
+  // debug-info will completely forget that this loop happened.
   if (RewritePhiSet.empty()) {
     // The loop exit value has been updated; insert the debug location
-    // for the given the induction variable with its final value.
+    // for the given induction variable with its final value.
     addDebugValuesToLoopVariable(L, SE, L->getInductionVariable(*SE));
   }
 

>From 042722466d4ee8f874c3bb1e8d0e6425e2e2d83b Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <carlos.alberto.enciso at gmail.com>
Date: Wed, 13 Mar 2024 17:20:36 +0000
Subject: [PATCH 07/11] [indvars] Missing variables at Og:

https://bugs.llvm.org/show_bug.cgi?id=51735
https://github.com/llvm/llvm-project/issues/51077

After internal discussion with @jmorse, it was decided
to split the work between the 'indvars' and the
'loop-deletion' passes.

1) passes="loop(indvars)"
- 'indvars' transformation is fired:
  the 'rewriteLoopExitValues' will rewrite the collected
  PNs with the exit values.
- 'indvars' transformation is not fired:
  If the loop can be deleted, we preserve the induction
  variable information to be used by 'loop-deletion' if
  that pass will be executed.

2) passes="loop(indvars,loop-deletion)"
  If the loop is deleted in 'deleteDeadLoop' and there
  is a valid exit block, we use any collected values
  by 'indvars' to updated the exit values.

Added extra tests to cover the following cases:
  ...
  char Var = 1;
  for (; Index < End; ++Index)
    if (Index == 666)
      ++Var;
  ...

and
  ...
  char Var = 1;
  for (; Index < End; ++Index)
    if (Index == 666)
      Var = 555;
  ...

Modified but otherwise unused variable 'Var' in a loop
that gets deleted.
---
 llvm/include/llvm/Support/GenericLoopInfo.h   |  24 ++++
 .../include/llvm/Transforms/Utils/LoopUtils.h |   1 -
 llvm/lib/Transforms/Utils/LoopUtils.cpp       |  62 ++++----
 .../pr51735-1.ll                              |  11 +-
 .../Transforms/IndVarSimplify/pr51735-2.ll    | 129 +++++++++++++++++
 .../Transforms/IndVarSimplify/pr51735-3.ll    | 132 ++++++++++++++++++
 .../pr51735.ll                                |  36 +++--
 7 files changed, 357 insertions(+), 38 deletions(-)
 rename llvm/test/Transforms/{LoopSimplify => IndVarSimplify}/pr51735-1.ll (91%)
 create mode 100644 llvm/test/Transforms/IndVarSimplify/pr51735-2.ll
 create mode 100644 llvm/test/Transforms/IndVarSimplify/pr51735-3.ll
 rename llvm/test/Transforms/{LoopSimplify => IndVarSimplify}/pr51735.ll (71%)

diff --git a/llvm/include/llvm/Support/GenericLoopInfo.h b/llvm/include/llvm/Support/GenericLoopInfo.h
index d560ca648132c9..f4b50367bf93d7 100644
--- a/llvm/include/llvm/Support/GenericLoopInfo.h
+++ b/llvm/include/llvm/Support/GenericLoopInfo.h
@@ -44,6 +44,8 @@
 #include "llvm/ADT/PostOrderIterator.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetOperations.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/ValueHandle.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/GenericDomTree.h"
 
@@ -75,6 +77,13 @@ template <class BlockT, class LoopT> class LoopBase {
   const LoopBase<BlockT, LoopT> &
   operator=(const LoopBase<BlockT, LoopT> &) = delete;
 
+  // Induction variable exit value and its debug users, preserved by the
+  // 'indvars' pass, when it detects that the loop can be deleted and the
+  // there are no PHIs to be rewritten.
+  // For now, we only preserve single induction variables.
+  Value *IndVarFinalValue = nullptr;
+  SmallVector<WeakVH> IndVarDebugUsers;
+
 public:
   /// Return the nesting level of this loop.  An outer-most loop has depth 1,
   /// for consistency with loop depth values used for basic blocks, where depth
@@ -251,6 +260,21 @@ template <class BlockT, class LoopT> class LoopBase {
                           [&](BlockT *Pred) { return contains(Pred); });
   }
 
+  /// Preserve the induction variable exit value and its debug users by the
+  /// 'indvars' pass if the loop can deleted. Those debug users will be used
+  /// by the 'loop-delete' pass.
+  void preserveDebugInductionVariableInfo(
+      Value *FinalValue, SmallVector<DbgVariableIntrinsic *> DbgUsers) {
+    IndVarFinalValue = FinalValue;
+    for (DbgVariableIntrinsic *DebugUser : DbgUsers)
+      IndVarDebugUsers.push_back(DebugUser);
+  }
+
+  Value *getDebugInductionVariableFinalValue() { return IndVarFinalValue; }
+  SmallVector<WeakVH> &getDebugInductionVariableDebugUsers() {
+    return IndVarDebugUsers;
+  }
+
   //===--------------------------------------------------------------------===//
   // APIs for simple analysis of the loop.
   //
diff --git a/llvm/include/llvm/Transforms/Utils/LoopUtils.h b/llvm/include/llvm/Transforms/Utils/LoopUtils.h
index cb4c92f7318374..736f4a630c7b3e 100644
--- a/llvm/include/llvm/Transforms/Utils/LoopUtils.h
+++ b/llvm/include/llvm/Transforms/Utils/LoopUtils.h
@@ -482,7 +482,6 @@ void addDebugValuesToIncomingValue(BasicBlock *Successor, Value *IndVar,
                                    PHINode *PN);
 void addDebugValuesToLoopVariable(BasicBlock *Successor, Value *ExitValue,
                                   PHINode *PN);
-void addDebugValuesToLoopVariable(Loop *L, ScalarEvolution *SE, PHINode *PN);
 
 /// Set weights for \p UnrolledLoop and \p RemainderLoop based on weights for
 /// \p OrigLoop and the following distribution of \p OrigLoop iteration among \p
diff --git a/llvm/lib/Transforms/Utils/LoopUtils.cpp b/llvm/lib/Transforms/Utils/LoopUtils.cpp
index 716075d13ef697..7ed7c0f83dbadd 100644
--- a/llvm/lib/Transforms/Utils/LoopUtils.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUtils.cpp
@@ -608,6 +608,17 @@ void llvm::deleteDeadLoop(Loop *L, DominatorTree *DT, ScalarEvolution *SE,
   llvm::SmallVector<DPValue *, 4> DeadDPValues;
 
   if (ExitBlock) {
+    if (ExitBlock->phis().empty()) {
+      // As the loop is deleted, replace the debug users with the preserved
+      // induction variable final value recorded by the 'indvar' pass.
+      Value *FinalValue = L->getDebugInductionVariableFinalValue();
+      SmallVector<WeakVH> &DbgUsers = L->getDebugInductionVariableDebugUsers();
+      for (WeakVH &DebugUser : DbgUsers)
+        if (DebugUser)
+          dyn_cast<DbgVariableIntrinsic>(DebugUser)->replaceVariableLocationOp(
+              0u, FinalValue);
+    }
+
     // Given LCSSA form is satisfied, we should not have users of instructions
     // within the dead loop outside of the loop. However, LCSSA doesn't take
     // unreachable uses into account. We handle them here.
@@ -1418,6 +1429,10 @@ void llvm::addDebugValuesToIncomingValue(BasicBlock *Successor, Value *IndVar,
   SmallVector<DbgVariableIntrinsic *> DbgUsers;
   findDbgUsers(DbgUsers, IndVar);
   for (auto *DebugUser : DbgUsers) {
+    // Skip debug-users with variadic variable locations; they will not,
+    // get updated, which is fine as that is the existing behaviour.
+    if (DebugUser->hasArgList())
+      continue;
     auto *Cloned = cast<DbgVariableIntrinsic>(DebugUser->clone());
     Cloned->replaceVariableLocationOp(0u, PN);
     Cloned->insertBefore(Successor->getFirstNonPHI());
@@ -1439,20 +1454,6 @@ void llvm::addDebugValuesToLoopVariable(BasicBlock *Successor, Value *ExitValue,
   }
 }
 
-void llvm::addDebugValuesToLoopVariable(Loop *L, ScalarEvolution *SE,
-                                        PHINode *PN) {
-  if (!PN)
-    return;
-  const SCEV *PNSCEV = SE->getSCEVAtScope(PN, L->getParentLoop());
-  if (auto *Const = dyn_cast<SCEVConstant>(PNSCEV)) {
-    Value *FinalIVValue = Const->getValue();
-    SmallVector<BasicBlock *> ExitBlocks;
-    L->getExitBlocks(ExitBlocks);
-    for (BasicBlock *Exit : ExitBlocks)
-      addDebugValuesToLoopVariable(Exit, FinalIVValue, PN);
-  }
-}
-
 int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
                                 ScalarEvolution *SE,
                                 const TargetTransformInfo *TTI,
@@ -1595,12 +1596,9 @@ int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
           &*Inst->getParent()->getFirstInsertionPt() : Inst;
         RewritePhiSet.emplace_back(PN, i, ExitValue, InsertPt, HighCost);
 
-        // Add debug values if the PN is a induction variable.
-        PHINode *IndVar = L->getInductionVariable(*SE);
-        if (PN->getIncomingValue(i) == IndVar)
-          if (BasicBlock *Successor = ExitBB->getSingleSuccessor())
-            addDebugValuesToIncomingValue(Successor, PN->getIncomingValue(i),
-                                          PN);
+        // Add debug values for the candidate PHINode incoming value.
+        if (BasicBlock *Successor = ExitBB->getSingleSuccessor())
+          addDebugValuesToIncomingValue(Successor, PN->getIncomingValue(i), PN);
       }
     }
   }
@@ -1665,14 +1663,22 @@ int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
     }
   }
 
-  // If there are no PHIs to be rewritten then there are no loop live-out
-  // values, try to rewrite debug variables corresponding to the induction
-  // variable with their constant exit-values if we computed any. Otherwise
-  // debug-info will completely forget that this loop happened.
-  if (RewritePhiSet.empty()) {
-    // The loop exit value has been updated; insert the debug location
-    // for the given induction variable with its final value.
-    addDebugValuesToLoopVariable(L, SE, L->getInductionVariable(*SE));
+  // If the loop can be deleted and there are no PHIs to be rewritten (there
+  // are no loop live-out values), record debug variables corresponding to the
+  // induction variable with their constant exit-values. Those values will be
+  // inserted by the 'deletion loop' logic.
+  if (LoopCanBeDel && RewritePhiSet.empty()) {
+    if (auto *IndVar = L->getInductionVariable(*SE)) {
+      const SCEV *PNSCEV = SE->getSCEVAtScope(IndVar, L->getParentLoop());
+      if (auto *Const = dyn_cast<SCEVConstant>(PNSCEV)) {
+        Value *FinalIVValue = Const->getValue();
+        if (L->getUniqueExitBlock()) {
+          SmallVector<DbgVariableIntrinsic *> DbgUsers;
+          findDbgUsers(DbgUsers, IndVar);
+          L->preserveDebugInductionVariableInfo(FinalIVValue, DbgUsers);
+        }
+      }
+    }
   }
 
   // The insertion point instruction may have been deleted; clear it out
diff --git a/llvm/test/Transforms/LoopSimplify/pr51735-1.ll b/llvm/test/Transforms/IndVarSimplify/pr51735-1.ll
similarity index 91%
rename from llvm/test/Transforms/LoopSimplify/pr51735-1.ll
rename to llvm/test/Transforms/IndVarSimplify/pr51735-1.ll
index 20cadcac47b60f..f7143fd8217200 100644
--- a/llvm/test/Transforms/LoopSimplify/pr51735-1.ll
+++ b/llvm/test/Transforms/IndVarSimplify/pr51735-1.ll
@@ -1,8 +1,17 @@
-; RUN: opt -passes=indvars -S -o - < %s | FileCheck %s
+; RUN: opt -passes="loop(indvars)" \
+; RUN:     --experimental-debuginfo-iterators=false -S -o - < %s | \
+; RUN: FileCheck --check-prefix=CHECK %s
+; RUN: opt -passes="loop(indvars,loop-deletion)" \
+; RUN:     --experimental-debuginfo-iterators=false -S -o - < %s | \
+; RUN: FileCheck --check-prefix=CHECK %s
 
 ; Make sure that when we delete the loop, that the variable Index has
 ; the 777 value.
 
+; As this test case does fire the 'indvars' transformation, the debug values
+; are added to the 'for.end' exit block. No debug values are preserved by the
+; pass to be used by the 'loop-deletion' pass.
+
 ; CHECK: for.cond:
 ; CHECK:   call void @llvm.dbg.value(metadata i32 %Index.0, metadata ![[DBG:[0-9]+]], {{.*}}
 
diff --git a/llvm/test/Transforms/IndVarSimplify/pr51735-2.ll b/llvm/test/Transforms/IndVarSimplify/pr51735-2.ll
new file mode 100644
index 00000000000000..fb43513bea8e8b
--- /dev/null
+++ b/llvm/test/Transforms/IndVarSimplify/pr51735-2.ll
@@ -0,0 +1,129 @@
+; RUN: opt -passes="loop(indvars)" \
+; RUN:     --experimental-debuginfo-iterators=false -S -o - < %s | \
+; RUN: FileCheck --implicit-check-not="call void @llvm.dbg" \
+; RUN:           --check-prefix=ALL-CHECK --check-prefix=PRE-CHECK %s
+; RUN: opt -passes="loop(indvars,loop-deletion)" \
+; RUN:     --experimental-debuginfo-iterators=false -S -o - < %s | \
+; RUN: FileCheck --implicit-check-not="call void @llvm.dbg" \
+; RUN:           --check-prefix=ALL-CHECK --check-prefix=POST-CHECK %s
+
+; Check what happens to a modified but otherwise unused variable in a loop
+; that gets deleted. The assignment in the loop is 'forgotten' by LLVM and
+; doesn't appear in the debugging information. This behaviour is suboptimal,
+; but we want to know if it changes
+
+; For all cases, LLDB shows
+;   Var = <no location, value may have been optimized out>
+
+;  1	__attribute__((optnone)) int nop() {
+;  2	  return 0;
+;  3	}
+;  4
+;  5	void bar() {
+;  6    int End = 777;
+;  7	  int Index = 27;
+;  8	  char Var = 1;
+;  9	  for (; Index < End; ++Index) {
+; 10      if (Index == 666) {
+; 11        ++Var;
+; 12      }
+; 13    }
+; 14	  nop();
+; 15	}
+
+; ALL-CHECK: entry:
+; ALL-CHECK:   call void @llvm.dbg.value(metadata i32 1, metadata ![[DBG:[0-9]+]], {{.*}}
+
+; Only the 'indvars' pass is executed.
+; PRE-CHECK: for.cond:
+; PRE-CHECK:   call void @llvm.dbg.value(metadata i32 %Var.0, metadata ![[DBG]], {{.*}}
+; PRE-CHECK:   call void @llvm.dbg.value(metadata !DIArgList{{.*}}
+
+; PRE-CHECK: for.body:
+; PRE-CHECK:   %cmp1 = icmp eq i32 %Index.0, 666
+; PRE-CHECK:   %inc = add nsw i32 %Var.0, 1
+; PRE-CHECK:   %spec.select = select i1 %cmp1, i32 %inc, i32 %Var.0
+; PRE-CHECK:   call void @llvm.dbg.value(metadata i32 %spec.select, metadata ![[DBG]], {{.*}}
+; PRE-CHECK:   br label %for.cond
+
+; PRE-CHECK: for.end:
+; PRE-CHECK-NOT: call void @llvm.dbg.value
+; PRE-CHECK:   ret void
+; PRE-CHECK-DAG: ![[DBG]] = !DILocalVariable(name: "Var"{{.*}})
+
+; The 'indvars' and 'loop-deletion' passes are executed.
+; POST-CHECK: for.end:
+; POST-CHECK:   call void @llvm.dbg.value(metadata i32 undef, metadata ![[DBG:[0-9]+]], {{.*}}
+; POST-CHECK:   ret void
+; POST-CHECK-DAG: ![[DBG]] = !DILocalVariable(name: "Var"{{.*}})
+
+define dso_local void @_Z3barv() local_unnamed_addr !dbg !18 {
+entry:
+  call void @llvm.dbg.value(metadata i32 1, metadata !24, metadata !DIExpression()), !dbg !22
+  br label %for.cond, !dbg !25
+
+for.cond:                                         ; preds = %for.cond, %entry
+  %Index.0 = phi i32 [ 27, %entry ], [ %inc2, %for.body ], !dbg !22
+  %Var.0 = phi i32 [ 1, %entry ], [ %spec.select, %for.body ], !dbg !22
+  call void @llvm.dbg.value(metadata i32 %Var.0, metadata !24, metadata !DIExpression()), !dbg !22
+  %cmp = icmp ult i32 %Index.0, 777, !dbg !26
+  call void @llvm.dbg.value(metadata !DIArgList(i32 poison, i32 %Index.0), metadata !24, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_constu, 666, DW_OP_eq, DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_plus, DW_OP_stack_value)), !dbg !22
+  %inc2 = add nuw nsw i32 %Index.0, 1, !dbg !29
+  br i1 %cmp, label %for.body, label %for.end, !dbg !30, !llvm.loop !31
+
+for.body:                                         ; preds = %for.cond
+  %cmp1 = icmp eq i32 %Index.0, 666, !dbg !30
+  %inc = add nsw i32 %Var.0, 1
+  %spec.select = select i1 %cmp1, i32 %inc, i32 %Var.0, !dbg !32
+  call void @llvm.dbg.value(metadata i32 %spec.select, metadata !24, metadata !DIExpression()), !dbg !22
+  br label %for.cond, !dbg !34, !llvm.loop !35
+
+for.end:                                          ; preds = %for.cond
+  ret void, !dbg !35
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "test-b.cpp", directory: "")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"PIE Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{i32 7, !"frame-pointer", i32 2}
+!9 = !{!"clang version 19.0.0"}
+!10 = distinct !DISubprogram(name: "nop", linkageName: "_Z3nopi", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14)
+!11 = !DISubroutineType(types: !12)
+!12 = !{!13, !13}
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!14 = !{}
+!15 = !DILocalVariable(name: "Param", arg: 1, scope: !10, file: !1, line: 1, type: !13)
+!16 = !DILocation(line: 1, column: 38, scope: !10)
+!17 = !DILocation(line: 2, column: 3, scope: !10)
+!18 = distinct !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 5, type: !19, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14)
+!19 = !DISubroutineType(types: !20)
+!20 = !{null}
+!22 = !DILocation(line: 0, scope: !18)
+!24 = !DILocalVariable(name: "Var", scope: !18, file: !1, line: 8, type: !13)
+!25 = !DILocation(line: 9, column: 3, scope: !18)
+!26 = !DILocation(line: 9, column: 16, scope: !27)
+!27 = distinct !DILexicalBlock(scope: !28, file: !1, line: 9, column: 3)
+!28 = distinct !DILexicalBlock(scope: !18, file: !1, line: 9, column: 3)
+!29 = !DILocation(line: 9, column: 23, scope: !27)
+!30 = !DILocation(line: 9, column: 3, scope: !28)
+!31 = distinct !{!31, !30, !32, !33}
+!32 = !DILocation(line: 11, column: 9, scope: !28)
+!33 = !{!"llvm.loop.mustprogress"}
+!34 = !DILocation(line: 12, column: 3, scope: !18)
+!35 = !DILocation(line: 13, column: 1, scope: !18)
+!36 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 15, type: !37, scopeLine: 15, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
+!37 = !DISubroutineType(types: !38)
+!38 = !{!13}
+!39 = !DILocation(line: 16, column: 3, scope: !36)
+!40 = !DILocation(line: 17, column: 1, scope: !36)
diff --git a/llvm/test/Transforms/IndVarSimplify/pr51735-3.ll b/llvm/test/Transforms/IndVarSimplify/pr51735-3.ll
new file mode 100644
index 00000000000000..947967ba1a8ef4
--- /dev/null
+++ b/llvm/test/Transforms/IndVarSimplify/pr51735-3.ll
@@ -0,0 +1,132 @@
+; RUN: opt -passes="loop(indvars)" \
+; RUN:     --experimental-debuginfo-iterators=false -S -o - < %s | \
+; RUN: FileCheck --implicit-check-not="call void @llvm.dbg" \
+; RUN:           --check-prefix=ALL-CHECK --check-prefix=PRE-CHECK %s
+; RUN: opt -passes="loop(indvars,loop-deletion)" \
+; RUN:     --experimental-debuginfo-iterators=false -S -o - < %s | \
+; RUN: FileCheck --implicit-check-not="call void @llvm.dbg" \
+; RUN:           --check-prefix=ALL-CHECK --check-prefix=POST-CHECK %s
+
+; Check what happens to a modified but otherwise unused variable in a loop
+; that gets deleted. The assignment in the loop is 'forgotten' by LLVM and
+; doesn't appear in the debugging information. This behaviour is suboptimal,
+; but we want to know if it changes
+
+; For all cases, LLDB shows
+;   Var = <no location, value may have been optimized out>
+
+;  1	__attribute__((optnone)) int nop() {
+;  2	  return 0;
+;  3	}
+;  4
+;  5	void bar() {
+;  6    int End = 777;
+;  7	  int Index = 27;
+;  8	  char Var = 1;
+;  9	  for (; Index < End; ++Index) {
+; 10      if (Index == 666) {
+; 11        Var = 555;
+; 12      }
+; 13    }
+; 14	  nop();
+; 15	}
+
+; ALL-CHECK: entry:
+; ALL-CHECK:   call void @llvm.dbg.value(metadata i32 1, metadata ![[DBG:[0-9]+]], {{.*}}
+
+; Only the 'indvars' pass is executed.
+; PRE-CHECK: if.then:
+; PRE-CHECK:   call void @llvm.dbg.value(metadata i32 555, metadata ![[DBG]], {{.*}}
+
+; PRE-CHECK: for.inc:
+; PRE-CHECK:   %Var.0 = phi i32 [ 1, %for.body ], [ 555, %if.then ]
+; PRE-CHECK:   call void @llvm.dbg.value(metadata i32 %Var.0, metadata ![[DBG]], {{.*}}
+; PRE-CHECK:   %inc = add nuw nsw i32 %Index.0, 1
+; PRE-CHECK:   br label %for.cond
+
+; PRE-CHECK: for.end:
+; PRE-CHECK-NOT: call void @llvm.dbg.value
+; PRE-CHECK:   ret void
+; PRE-CHECK-DAG: ![[DBG]] = !DILocalVariable(name: "Var"{{.*}})
+
+; The 'indvars' and 'loop-deletion' passes are executed.
+; POST-CHECK: for.end:
+; POST-CHECK:   call void @llvm.dbg.value(metadata i32 555, metadata ![[DBG]], {{.*}}
+; POST-CHECK:   ret void
+; POST-CHECK-DAG: ![[DBG]] = !DILocalVariable(name: "Var"{{.*}})
+
+define dso_local void @_Z3barv() local_unnamed_addr !dbg !18 {
+entry:
+  call void @llvm.dbg.value(metadata i32 1, metadata !24, metadata !DIExpression()), !dbg !22
+  br label %for.cond, !dbg !25
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %Index.0 = phi i32 [ 27, %entry ], [ %inc, %for.inc ], !dbg !22
+  %cmp = icmp ult i32 %Index.0, 777, !dbg !26
+  br i1 %cmp, label %for.body, label %for.end, !dbg !30, !llvm.loop !29
+
+for.body:                                         ; preds = %for.cond
+  %cmp1 = icmp eq i32 %Index.0, 666, !dbg !30
+  br i1 %cmp1, label %if.then, label %for.inc, !dbg !32
+
+if.then:                                          ; preds = %for.body
+  call void @llvm.dbg.value(metadata i32 555, metadata !24, metadata !DIExpression()), !dbg !22
+  br label %for.inc, !dbg !34, !llvm.loop !32
+
+for.inc:                                          ; preds = %for.body, %if.then
+  %Var.0 = phi i32 [ 1, %for.body ], [ 555, %if.then ], !dbg !22
+  call void @llvm.dbg.value(metadata i32 %Var.0, metadata !24, metadata !DIExpression()), !dbg !22
+  %inc = add nuw nsw i32 %Index.0, 1, !dbg !29
+  br label %for.cond, !dbg !34, !llvm.loop !35
+
+for.end:                                          ; preds = %for.cond
+  ret void, !dbg !35
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "test-c.cpp", directory: "")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"PIE Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{i32 7, !"frame-pointer", i32 2}
+!9 = !{!"clang version 19.0.0"}
+!10 = distinct !DISubprogram(name: "nop", linkageName: "_Z3nopi", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14)
+!11 = !DISubroutineType(types: !12)
+!12 = !{!13, !13}
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!14 = !{}
+!15 = !DILocalVariable(name: "Param", arg: 1, scope: !10, file: !1, line: 1, type: !13)
+!16 = !DILocation(line: 1, column: 38, scope: !10)
+!17 = !DILocation(line: 2, column: 3, scope: !10)
+!18 = distinct !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 5, type: !19, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14)
+!19 = !DISubroutineType(types: !20)
+!20 = !{null}
+!21 = !DILocalVariable(name: "End", scope: !18, file: !1, line: 6, type: !13)
+!22 = !DILocation(line: 0, scope: !18)
+!23 = !DILocalVariable(name: "Index", scope: !18, file: !1, line: 7, type: !13)
+!24 = !DILocalVariable(name: "Var", scope: !18, file: !1, line: 8, type: !13)
+!25 = !DILocation(line: 9, column: 3, scope: !18)
+!26 = !DILocation(line: 9, column: 16, scope: !27)
+!27 = distinct !DILexicalBlock(scope: !28, file: !1, line: 9, column: 3)
+!28 = distinct !DILexicalBlock(scope: !18, file: !1, line: 9, column: 3)
+!29 = !DILocation(line: 9, column: 23, scope: !27)
+!30 = !DILocation(line: 9, column: 3, scope: !28)
+!31 = distinct !{!31, !30, !32, !33}
+!32 = !DILocation(line: 11, column: 13, scope: !28)
+!33 = !{!"llvm.loop.mustprogress"}
+!34 = !DILocation(line: 12, column: 3, scope: !18)
+!35 = !DILocation(line: 13, column: 1, scope: !18)
+!36 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 15, type: !37, scopeLine: 15, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
+!37 = !DISubroutineType(types: !38)
+!38 = !{!13}
+!39 = !DILocation(line: 16, column: 3, scope: !36)
+!40 = !DILocation(line: 17, column: 1, scope: !36)
diff --git a/llvm/test/Transforms/LoopSimplify/pr51735.ll b/llvm/test/Transforms/IndVarSimplify/pr51735.ll
similarity index 71%
rename from llvm/test/Transforms/LoopSimplify/pr51735.ll
rename to llvm/test/Transforms/IndVarSimplify/pr51735.ll
index 5eb8bb50f33359..3014b3467852d1 100644
--- a/llvm/test/Transforms/LoopSimplify/pr51735.ll
+++ b/llvm/test/Transforms/IndVarSimplify/pr51735.ll
@@ -1,4 +1,9 @@
-; RUN: opt -passes=indvars -S -o - < %s | FileCheck %s
+; RUN: opt -passes="loop(indvars)" \
+; RUN:     --experimental-debuginfo-iterators=false -S -o - < %s | \
+; RUN: FileCheck --check-prefix=PRE-CHECK %s
+; RUN: opt -passes="loop(indvars,loop-deletion)" \
+; RUN:     --experimental-debuginfo-iterators=false -S -o - < %s | \
+; RUN: FileCheck --check-prefix=POST-CHECK %s
 
 ; Make sure that when we delete the loop in the code below, that the variable
 ; Index has the 777 value.
@@ -20,13 +25,28 @@
 ; 15	  bar();
 ; 16	}
 
-; CHECK: for.cond:
-; CHECK:   call void @llvm.dbg.value(metadata i32 poison, metadata ![[DBG:[0-9]+]], {{.*}}
-; CHECK:   call void @llvm.dbg.value(metadata i32 poison, metadata ![[DBG]], {{.*}}
-; CHECK:   br i1 false, label %for.cond, label %for.end, {{.*}}
-; CHECK: for.end:
-; CHECK:   call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG]], {{.*}}
-; CHECK-DAG: ![[DBG]] = !DILocalVariable(name: "Index"{{.*}})
+; Only the 'indvars' pass is executed.
+; As this test case does not fire the 'indvars' transformation, no debug values
+; are preserved and or added.
+
+; PRE-CHECK: for.cond:
+; PRE-CHECK:   call void @llvm.dbg.value(metadata i32 poison, metadata ![[DBG_1:[0-9]+]], {{.*}}
+; PRE-CHECK:   call void @llvm.dbg.value(metadata i32 poison, metadata ![[DBG_1]], {{.*}}
+; PRE-CHECK:   br i1 false, label %for.cond, label %for.end
+
+; PRE-CHECK: for.end:
+; PRE-CHECK-NOT: call void @llvm.dbg.value
+; PRE-CHECK:   ret void
+; PRE-CHECK-DAG: ![[DBG_1]] = !DILocalVariable(name: "Index"{{.*}})
+
+; The 'indvars' and 'loop-deletion' passes are executed.
+; The loop is deleted and the debug values collected by 'indvars' are used by
+; 'loop-deletion' to add the induction variable debug value.
+
+; POST-CHECK: for.end:
+; POST-CHECK:   call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG_2:[0-9]+]], {{.*}}
+; POST-CHECK:   ret void
+; POST-CHECK-DAG: ![[DBG_2]] = !DILocalVariable(name: "Index"{{.*}})
 
 define dso_local void @_Z3barv() local_unnamed_addr #1 !dbg !15 {
 entry:

>From ac8a3aa68b3a3a9a779b41a7b37cecb3ebbf0e11 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <carlos.alberto.enciso at gmail.com>
Date: Mon, 18 Mar 2024 08:11:50 +0000
Subject: [PATCH 08/11] [indvars] Missing variables at Og:

https://bugs.llvm.org/show_bug.cgi?id=51735
https://github.com/llvm/llvm-project/issues/51077

Address @SLTozer comments.
- Use captured variables for SSA values.
- Use new insert logic calls.
- Remove not required 'CHECK-NOT'.
---
 llvm/lib/Transforms/Utils/LoopUtils.cpp          |  6 +++---
 llvm/test/Transforms/IndVarSimplify/pr51735-1.ll | 10 +++++-----
 llvm/test/Transforms/IndVarSimplify/pr51735-2.ll |  9 ++++-----
 llvm/test/Transforms/IndVarSimplify/pr51735-3.ll |  7 +++----
 4 files changed, 15 insertions(+), 17 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/LoopUtils.cpp b/llvm/lib/Transforms/Utils/LoopUtils.cpp
index 7ed7c0f83dbadd..1ffd390ea5accc 100644
--- a/llvm/lib/Transforms/Utils/LoopUtils.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUtils.cpp
@@ -615,7 +615,7 @@ void llvm::deleteDeadLoop(Loop *L, DominatorTree *DT, ScalarEvolution *SE,
       SmallVector<WeakVH> &DbgUsers = L->getDebugInductionVariableDebugUsers();
       for (WeakVH &DebugUser : DbgUsers)
         if (DebugUser)
-          dyn_cast<DbgVariableIntrinsic>(DebugUser)->replaceVariableLocationOp(
+          cast<DbgVariableIntrinsic>(DebugUser)->replaceVariableLocationOp(
               0u, FinalValue);
     }
 
@@ -1435,7 +1435,7 @@ void llvm::addDebugValuesToIncomingValue(BasicBlock *Successor, Value *IndVar,
       continue;
     auto *Cloned = cast<DbgVariableIntrinsic>(DebugUser->clone());
     Cloned->replaceVariableLocationOp(0u, PN);
-    Cloned->insertBefore(Successor->getFirstNonPHI());
+    Cloned->insertBefore(*Successor, Successor->getFirstNonPHIIt());
   }
 }
 
@@ -1450,7 +1450,7 @@ void llvm::addDebugValuesToLoopVariable(BasicBlock *Successor, Value *ExitValue,
       continue;
     auto *Cloned = cast<DbgVariableIntrinsic>(DebugUser->clone());
     Cloned->replaceVariableLocationOp(0u, ExitValue);
-    Cloned->insertBefore(Successor->getFirstNonPHI());
+    Cloned->insertBefore(*Successor, Successor->getFirstNonPHIIt());
   }
 }
 
diff --git a/llvm/test/Transforms/IndVarSimplify/pr51735-1.ll b/llvm/test/Transforms/IndVarSimplify/pr51735-1.ll
index f7143fd8217200..356217985fed11 100644
--- a/llvm/test/Transforms/IndVarSimplify/pr51735-1.ll
+++ b/llvm/test/Transforms/IndVarSimplify/pr51735-1.ll
@@ -13,19 +13,19 @@
 ; pass to be used by the 'loop-deletion' pass.
 
 ; CHECK: for.cond:
-; CHECK:   call void @llvm.dbg.value(metadata i32 %Index.0, metadata ![[DBG:[0-9]+]], {{.*}}
+; CHECK:   call void @llvm.dbg.value(metadata i32 %[[SSA_INDEX_0:.+]], metadata ![[DBG:[0-9]+]], {{.*}}
 
 ; CHECK: for.extra:
-; CHECK:   %call.0 = call noundef i32 @"?nop@@YAHH at Z"(i32 noundef %Index.0), {{.*}}
-; CHECK:   br i1 %cmp.0, label %for.cond, label %if.else, {{.*}}
+; CHECK:   %[[SSA_CALL_0:.+]] = call noundef i32 @"?nop@@YAHH at Z"(i32 noundef %[[SSA_INDEX_0]]), {{.*}}
+; CHECK:   br i1 %[[SSA_CMP_0:.+]], label %for.cond, label %if.else, {{.*}}
 
 ; CHECK: if.then:
 ; CHECK:   call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG]], {{.*}}
-; CHECK:   call void @llvm.dbg.value(metadata i32 %Var.1, metadata ![[VAR:[0-9]+]], {{.*}}
+; CHECK:   call void @llvm.dbg.value(metadata i32 %[[SSA_VAR_1:.+]], metadata ![[VAR:[0-9]+]], {{.*}}
 ; CHECK:   br label %for.end, {{.*}}
 
 ; CHECK: if.else:
-; CHECK:   call void @llvm.dbg.value(metadata i32 %Var.2, metadata ![[VAR:[0-9]+]], {{.*}}
+; CHECK:   call void @llvm.dbg.value(metadata i32 %[[SSA_VAR_2:.+]], metadata ![[VAR:[0-9]+]], {{.*}}
 ; CHECK:   br label %for.end, {{.*}}
 
 ; CHECK: for.end:
diff --git a/llvm/test/Transforms/IndVarSimplify/pr51735-2.ll b/llvm/test/Transforms/IndVarSimplify/pr51735-2.ll
index fb43513bea8e8b..734e33906e18b9 100644
--- a/llvm/test/Transforms/IndVarSimplify/pr51735-2.ll
+++ b/llvm/test/Transforms/IndVarSimplify/pr51735-2.ll
@@ -36,18 +36,17 @@
 
 ; Only the 'indvars' pass is executed.
 ; PRE-CHECK: for.cond:
-; PRE-CHECK:   call void @llvm.dbg.value(metadata i32 %Var.0, metadata ![[DBG]], {{.*}}
+; PRE-CHECK:   call void @llvm.dbg.value(metadata i32 %[[SSA_VAR_0:.+]], metadata ![[DBG]], {{.*}}
 ; PRE-CHECK:   call void @llvm.dbg.value(metadata !DIArgList{{.*}}
 
 ; PRE-CHECK: for.body:
-; PRE-CHECK:   %cmp1 = icmp eq i32 %Index.0, 666
-; PRE-CHECK:   %inc = add nsw i32 %Var.0, 1
-; PRE-CHECK:   %spec.select = select i1 %cmp1, i32 %inc, i32 %Var.0
+; PRE-CHECK:   %cmp1 = icmp eq i32 %[[SSA_INDEX_0:.+]], 666
+; PRE-CHECK:   %inc = add nsw i32 %[[SSA_VAR_0]], 1
+; PRE-CHECK:   %spec.select = select i1 %cmp1, i32 %inc, i32 %[[SSA_VAR_0]]
 ; PRE-CHECK:   call void @llvm.dbg.value(metadata i32 %spec.select, metadata ![[DBG]], {{.*}}
 ; PRE-CHECK:   br label %for.cond
 
 ; PRE-CHECK: for.end:
-; PRE-CHECK-NOT: call void @llvm.dbg.value
 ; PRE-CHECK:   ret void
 ; PRE-CHECK-DAG: ![[DBG]] = !DILocalVariable(name: "Var"{{.*}})
 
diff --git a/llvm/test/Transforms/IndVarSimplify/pr51735-3.ll b/llvm/test/Transforms/IndVarSimplify/pr51735-3.ll
index 947967ba1a8ef4..72c6795cd25e45 100644
--- a/llvm/test/Transforms/IndVarSimplify/pr51735-3.ll
+++ b/llvm/test/Transforms/IndVarSimplify/pr51735-3.ll
@@ -39,13 +39,12 @@
 ; PRE-CHECK:   call void @llvm.dbg.value(metadata i32 555, metadata ![[DBG]], {{.*}}
 
 ; PRE-CHECK: for.inc:
-; PRE-CHECK:   %Var.0 = phi i32 [ 1, %for.body ], [ 555, %if.then ]
-; PRE-CHECK:   call void @llvm.dbg.value(metadata i32 %Var.0, metadata ![[DBG]], {{.*}}
-; PRE-CHECK:   %inc = add nuw nsw i32 %Index.0, 1
+; PRE-CHECK:   %[[SSA_VAR_0:.+]] = phi i32 [ 1, %for.body ], [ 555, %if.then ]
+; PRE-CHECK:   call void @llvm.dbg.value(metadata i32 %[[SSA_VAR_0]], metadata ![[DBG]], {{.*}}
+; PRE-CHECK:   %inc = add nuw nsw i32 %[[SSA_INDEX_0:.+]], 1
 ; PRE-CHECK:   br label %for.cond
 
 ; PRE-CHECK: for.end:
-; PRE-CHECK-NOT: call void @llvm.dbg.value
 ; PRE-CHECK:   ret void
 ; PRE-CHECK-DAG: ![[DBG]] = !DILocalVariable(name: "Var"{{.*}})
 

>From 9e4c629384b485fe0cc871882aeeea243dcbea67 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <carlos.alberto.enciso at gmail.com>
Date: Tue, 19 Mar 2024 13:56:37 +0000
Subject: [PATCH 09/11] [indvars] Missing variables at Og:

https://bugs.llvm.org/show_bug.cgi?id=51735
https://github.com/llvm/llvm-project/issues/51077

Address @SLTozer comments.
- Don't use any names for not used SSA values.
---
 llvm/test/Transforms/IndVarSimplify/pr51735-2.ll | 8 ++++----
 llvm/test/Transforms/IndVarSimplify/pr51735-3.ll | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/llvm/test/Transforms/IndVarSimplify/pr51735-2.ll b/llvm/test/Transforms/IndVarSimplify/pr51735-2.ll
index 734e33906e18b9..58cc9932e04ca8 100644
--- a/llvm/test/Transforms/IndVarSimplify/pr51735-2.ll
+++ b/llvm/test/Transforms/IndVarSimplify/pr51735-2.ll
@@ -40,10 +40,10 @@
 ; PRE-CHECK:   call void @llvm.dbg.value(metadata !DIArgList{{.*}}
 
 ; PRE-CHECK: for.body:
-; PRE-CHECK:   %cmp1 = icmp eq i32 %[[SSA_INDEX_0:.+]], 666
-; PRE-CHECK:   %inc = add nsw i32 %[[SSA_VAR_0]], 1
-; PRE-CHECK:   %spec.select = select i1 %cmp1, i32 %inc, i32 %[[SSA_VAR_0]]
-; PRE-CHECK:   call void @llvm.dbg.value(metadata i32 %spec.select, metadata ![[DBG]], {{.*}}
+; PRE-CHECK:   {{.*}} = icmp eq i32 %[[SSA_INDEX_0:.+]], 666
+; PRE-CHECK:   {{.*}} = add nsw i32 %[[SSA_VAR_0]], 1
+; PRE-CHECK:   {{.*}} = select i1 {{.*}}, i32 {{.*}}, i32 %[[SSA_VAR_0]]
+; PRE-CHECK:   call void @llvm.dbg.value(metadata i32 {{.*}}, metadata ![[DBG]], {{.*}}
 ; PRE-CHECK:   br label %for.cond
 
 ; PRE-CHECK: for.end:
diff --git a/llvm/test/Transforms/IndVarSimplify/pr51735-3.ll b/llvm/test/Transforms/IndVarSimplify/pr51735-3.ll
index 72c6795cd25e45..ac9964743e0ffc 100644
--- a/llvm/test/Transforms/IndVarSimplify/pr51735-3.ll
+++ b/llvm/test/Transforms/IndVarSimplify/pr51735-3.ll
@@ -41,7 +41,7 @@
 ; PRE-CHECK: for.inc:
 ; PRE-CHECK:   %[[SSA_VAR_0:.+]] = phi i32 [ 1, %for.body ], [ 555, %if.then ]
 ; PRE-CHECK:   call void @llvm.dbg.value(metadata i32 %[[SSA_VAR_0]], metadata ![[DBG]], {{.*}}
-; PRE-CHECK:   %inc = add nuw nsw i32 %[[SSA_INDEX_0:.+]], 1
+; PRE-CHECK:   {{.*}} = add nuw nsw i32 %[[SSA_INDEX_0:.+]], 1
 ; PRE-CHECK:   br label %for.cond
 
 ; PRE-CHECK: for.end:

>From 6187569017d67875652be19628413b748fd19d07 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso
 <47597242+CarlosAlbertoEnciso at users.noreply.github.com>
Date: Wed, 10 Apr 2024 13:38:50 +0100
Subject: [PATCH 10/11] [indvars] Missing variables at Og:

https://bugs.llvm.org/show_bug.cgi?id=51735
https://github.com/llvm/llvm-project/issues/51077

Address @nikic comments about layering violation.
- Move code to 'LoopInfo.h'.
---
 llvm/include/llvm/Analysis/LoopInfo.h       | 24 +++++++++++++++++++++
 llvm/include/llvm/Support/GenericLoopInfo.h | 24 ---------------------
 2 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/llvm/include/llvm/Analysis/LoopInfo.h b/llvm/include/llvm/Analysis/LoopInfo.h
index 52084630560c55..072ca4ee479923 100644
--- a/llvm/include/llvm/Analysis/LoopInfo.h
+++ b/llvm/include/llvm/Analysis/LoopInfo.h
@@ -18,6 +18,8 @@
 #include "llvm/IR/CFG.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/PassManager.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/ValueHandle.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/GenericLoopInfo.h"
 #include <algorithm>
@@ -392,6 +394,21 @@ class LLVM_EXTERNAL_VISIBILITY Loop : public LoopBase<BasicBlock, Loop> {
     return "<unnamed loop>";
   }
 
+  /// Preserve the induction variable exit value and its debug users by the
+  /// 'indvars' pass if the loop can deleted. Those debug users will be used
+  /// by the 'loop-delete' pass.
+  void preserveDebugInductionVariableInfo(
+      Value *FinalValue, SmallVector<DbgVariableIntrinsic *> DbgUsers) {
+    IndVarFinalValue = FinalValue;
+    for (DbgVariableIntrinsic *DebugUser : DbgUsers)
+      IndVarDebugUsers.push_back(DebugUser);
+  }
+
+  Value *getDebugInductionVariableFinalValue() { return IndVarFinalValue; }
+  SmallVector<WeakVH> &getDebugInductionVariableDebugUsers() {
+    return IndVarDebugUsers;
+  }
+
 private:
   Loop() = default;
 
@@ -399,6 +416,13 @@ class LLVM_EXTERNAL_VISIBILITY Loop : public LoopBase<BasicBlock, Loop> {
   friend class LoopBase<BasicBlock, Loop>;
   explicit Loop(BasicBlock *BB) : LoopBase<BasicBlock, Loop>(BB) {}
   ~Loop() = default;
+
+  // Induction variable exit value and its debug users, preserved by the
+  // 'indvars' pass, when it detects that the loop can be deleted and the
+  // there are no PHIs to be rewritten.
+  // For now, we only preserve single induction variables.
+  Value *IndVarFinalValue = nullptr;
+  SmallVector<WeakVH> IndVarDebugUsers;
 };
 
 // Implementation in Support/GenericLoopInfoImpl.h
diff --git a/llvm/include/llvm/Support/GenericLoopInfo.h b/llvm/include/llvm/Support/GenericLoopInfo.h
index f4b50367bf93d7..d560ca648132c9 100644
--- a/llvm/include/llvm/Support/GenericLoopInfo.h
+++ b/llvm/include/llvm/Support/GenericLoopInfo.h
@@ -44,8 +44,6 @@
 #include "llvm/ADT/PostOrderIterator.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetOperations.h"
-#include "llvm/IR/IntrinsicInst.h"
-#include "llvm/IR/ValueHandle.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/GenericDomTree.h"
 
@@ -77,13 +75,6 @@ template <class BlockT, class LoopT> class LoopBase {
   const LoopBase<BlockT, LoopT> &
   operator=(const LoopBase<BlockT, LoopT> &) = delete;
 
-  // Induction variable exit value and its debug users, preserved by the
-  // 'indvars' pass, when it detects that the loop can be deleted and the
-  // there are no PHIs to be rewritten.
-  // For now, we only preserve single induction variables.
-  Value *IndVarFinalValue = nullptr;
-  SmallVector<WeakVH> IndVarDebugUsers;
-
 public:
   /// Return the nesting level of this loop.  An outer-most loop has depth 1,
   /// for consistency with loop depth values used for basic blocks, where depth
@@ -260,21 +251,6 @@ template <class BlockT, class LoopT> class LoopBase {
                           [&](BlockT *Pred) { return contains(Pred); });
   }
 
-  /// Preserve the induction variable exit value and its debug users by the
-  /// 'indvars' pass if the loop can deleted. Those debug users will be used
-  /// by the 'loop-delete' pass.
-  void preserveDebugInductionVariableInfo(
-      Value *FinalValue, SmallVector<DbgVariableIntrinsic *> DbgUsers) {
-    IndVarFinalValue = FinalValue;
-    for (DbgVariableIntrinsic *DebugUser : DbgUsers)
-      IndVarDebugUsers.push_back(DebugUser);
-  }
-
-  Value *getDebugInductionVariableFinalValue() { return IndVarFinalValue; }
-  SmallVector<WeakVH> &getDebugInductionVariableDebugUsers() {
-    return IndVarDebugUsers;
-  }
-
   //===--------------------------------------------------------------------===//
   // APIs for simple analysis of the loop.
   //

>From 0d06af2e56a45b1319e85c91e0ff523a46b5362b Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso
 <47597242+CarlosAlbertoEnciso at users.noreply.github.com>
Date: Thu, 11 Apr 2024 05:08:58 +0100
Subject: [PATCH 11/11] [indvars] Missing variables at Og:

https://bugs.llvm.org/show_bug.cgi?id=51735
https://github.com/llvm/llvm-project/issues/51077

Fix Clang-format issue.
---
 llvm/include/llvm/Analysis/LoopInfo.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm/Analysis/LoopInfo.h b/llvm/include/llvm/Analysis/LoopInfo.h
index 072ca4ee479923..e8370bbea5735c 100644
--- a/llvm/include/llvm/Analysis/LoopInfo.h
+++ b/llvm/include/llvm/Analysis/LoopInfo.h
@@ -17,8 +17,8 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/IR/CFG.h"
 #include "llvm/IR/Instructions.h"
-#include "llvm/IR/PassManager.h"
 #include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/PassManager.h"
 #include "llvm/IR/ValueHandle.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/GenericLoopInfo.h"



More information about the llvm-commits mailing list