diff --git a/llvm/include/llvm/Transforms/Utils/LoopUtils.h b/llvm/include/llvm/Transforms/Utils/LoopUtils.h index 5a1385d01d8e44d..26230fe97f67867 100644 --- a/llvm/include/llvm/Transforms/Utils/LoopUtils.h +++ b/llvm/include/llvm/Transforms/Utils/LoopUtils.h @@ -468,6 +468,10 @@ int rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI, ReplaceExitVal ReplaceExitValue, SmallVector &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 2a6997c48883d44..41c4d6236173472 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 e52eff5837afb11..5109666500c3f9d 100644 --- a/llvm/lib/Transforms/Utils/LoopUtils.cpp +++ b/llvm/lib/Transforms/Utils/LoopUtils.cpp @@ -1342,6 +1342,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 ExitBlocks; + L->getExitBlocks(ExitBlocks); + SmallVector 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(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(PNSCEV)) { + Value *FinalIVValue = Const->getValue(); + addDebugValuesToLoopVariable(L, FinalIVValue, PN); + } +} + int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI, ScalarEvolution *SE, const TargetTransformInfo *TTI, @@ -1483,6 +1513,21 @@ int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI, (isa(Inst) || isa(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 DbgUsers; + findDbgUsers(DbgUsers, V); + for (auto *DebugUser : DbgUsers) { + auto *Cloned = cast(DebugUser->clone()); + Cloned->replaceVariableLocationOp(0u, PN); + Cloned->insertBefore(Successor->getFirstNonPHI()); + } + } + } } } } @@ -1541,39 +1586,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(IndVarSCEV)) { - Value *FinalIVValue = cast(IndVarSCEV)->getValue(); - SmallVector DbgUsers; - SmallVector DbgUsersCloned; - findDbgUsers(DbgUsers, IndVar); - for (auto &DebugUser : DbgUsers) { - auto *Cloned = cast(DebugUser->clone()); - Cloned->replaceVariableLocationOp(static_cast(0), - FinalIVValue); - DbgUsersCloned.push_back(Cloned); - } - - SmallVector 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 cb3e8fa43e3ecf6..293553b000c13cc 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@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@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@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@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@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 c86f8ed7d0274f0..5eb8bb50f333594 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 {