Skip to content

Commit 89e1f77

Browse files
[indvars] Missing variables at Og (#88270)
https://bugs.llvm.org/show_bug.cgi?id=51735 #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`.
1 parent 108575f commit 89e1f77

File tree

7 files changed

+588
-0
lines changed

7 files changed

+588
-0
lines changed

llvm/include/llvm/Analysis/LoopInfo.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
#include "llvm/ADT/SmallVector.h"
1818
#include "llvm/IR/CFG.h"
1919
#include "llvm/IR/Instructions.h"
20+
#include "llvm/IR/IntrinsicInst.h"
2021
#include "llvm/IR/PassManager.h"
22+
#include "llvm/IR/ValueHandle.h"
2123
#include "llvm/Pass.h"
2224
#include "llvm/Support/GenericLoopInfo.h"
2325
#include <algorithm>
@@ -392,13 +394,36 @@ class LLVM_EXTERNAL_VISIBILITY Loop : public LoopBase<BasicBlock, Loop> {
392394
return "<unnamed loop>";
393395
}
394396

397+
/// Preserve the induction variable exit value and its debug users by the
398+
/// 'indvars' pass if the loop can deleted. Those debug users will be used
399+
/// by the 'loop-delete' pass.
400+
void preserveDebugInductionVariableInfo(
401+
Value *FinalValue,
402+
const SmallVectorImpl<DbgVariableIntrinsic *> &DbgUsers) {
403+
IndVarFinalValue = FinalValue;
404+
for (auto &DebugUser : DbgUsers)
405+
IndVarDebugUsers.push_back(DebugUser);
406+
}
407+
408+
Value *getDebugInductionVariableFinalValue() { return IndVarFinalValue; }
409+
SmallVector<WeakVH> &getDebugInductionVariableDebugUsers() {
410+
return IndVarDebugUsers;
411+
}
412+
395413
private:
396414
Loop() = default;
397415

398416
friend class LoopInfoBase<BasicBlock, Loop>;
399417
friend class LoopBase<BasicBlock, Loop>;
400418
explicit Loop(BasicBlock *BB) : LoopBase<BasicBlock, Loop>(BB) {}
401419
~Loop() = default;
420+
421+
// Induction variable exit value and its debug users, preserved by the
422+
// 'indvars' pass, when it detects that the loop can be deleted and the
423+
// there are no PHIs to be rewritten.
424+
// For now, we only preserve single induction variables.
425+
Value *IndVarFinalValue = nullptr;
426+
SmallVector<WeakVH> IndVarDebugUsers;
402427
};
403428

404429
// Implementation in Support/GenericLoopInfoImpl.h

llvm/include/llvm/Transforms/Utils/LoopUtils.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,12 @@ int rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
468468
ReplaceExitVal ReplaceExitValue,
469469
SmallVector<WeakTrackingVH, 16> &DeadInsts);
470470

471+
/// Assign exit values to variables that use this loop variable during the loop.
472+
void addDebugValuesToIncomingValue(BasicBlock *Successor, Value *IndVar,
473+
PHINode *PN);
474+
void addDebugValuesToLoopVariable(BasicBlock *Successor, Value *ExitValue,
475+
PHINode *PN);
476+
471477
/// Set weights for \p UnrolledLoop and \p RemainderLoop based on weights for
472478
/// \p OrigLoop and the following distribution of \p OrigLoop iteration among \p
473479
/// UnrolledLoop and \p RemainderLoop. \p UnrolledLoop receives weights that

llvm/lib/Transforms/Utils/LoopUtils.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
3232
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
3333
#include "llvm/IR/DIBuilder.h"
34+
#include "llvm/IR/DebugInfo.h"
3435
#include "llvm/IR/Dominators.h"
3536
#include "llvm/IR/Instructions.h"
3637
#include "llvm/IR/IntrinsicInst.h"
@@ -608,6 +609,17 @@ void llvm::deleteDeadLoop(Loop *L, DominatorTree *DT, ScalarEvolution *SE,
608609
llvm::SmallVector<DbgVariableRecord *, 4> DeadDbgVariableRecords;
609610

610611
if (ExitBlock) {
612+
if (ExitBlock->phis().empty()) {
613+
// As the loop is deleted, replace the debug users with the preserved
614+
// induction variable final value recorded by the 'indvar' pass.
615+
Value *FinalValue = L->getDebugInductionVariableFinalValue();
616+
SmallVector<WeakVH> &DbgUsers = L->getDebugInductionVariableDebugUsers();
617+
for (WeakVH &DebugUser : DbgUsers)
618+
if (DebugUser)
619+
cast<DbgVariableIntrinsic>(DebugUser)->replaceVariableLocationOp(
620+
0u, FinalValue);
621+
}
622+
611623
// Given LCSSA form is satisfied, we should not have users of instructions
612624
// within the dead loop outside of the loop. However, LCSSA doesn't take
613625
// unreachable uses into account. We handle them here.
@@ -1401,6 +1413,36 @@ static bool checkIsIndPhi(PHINode *Phi, Loop *L, ScalarEvolution *SE,
14011413
return InductionDescriptor::isInductionPHI(Phi, L, SE, ID);
14021414
}
14031415

1416+
void llvm::addDebugValuesToIncomingValue(BasicBlock *Successor, Value *IndVar,
1417+
PHINode *PN) {
1418+
SmallVector<DbgVariableIntrinsic *> DbgUsers;
1419+
findDbgUsers(DbgUsers, IndVar);
1420+
for (auto *DebugUser : DbgUsers) {
1421+
// Skip debug-users with variadic variable locations; they will not,
1422+
// get updated, which is fine as that is the existing behaviour.
1423+
if (DebugUser->hasArgList())
1424+
continue;
1425+
auto *Cloned = cast<DbgVariableIntrinsic>(DebugUser->clone());
1426+
Cloned->replaceVariableLocationOp(0u, PN);
1427+
Cloned->insertBefore(*Successor, Successor->getFirstNonPHIIt());
1428+
}
1429+
}
1430+
1431+
void llvm::addDebugValuesToLoopVariable(BasicBlock *Successor, Value *ExitValue,
1432+
PHINode *PN) {
1433+
SmallVector<DbgVariableIntrinsic *> DbgUsers;
1434+
findDbgUsers(DbgUsers, PN);
1435+
for (auto *DebugUser : DbgUsers) {
1436+
// Skip debug-users with variadic variable locations; they will not,
1437+
// get updated, which is fine as that is the existing behaviour.
1438+
if (DebugUser->hasArgList())
1439+
continue;
1440+
auto *Cloned = cast<DbgVariableIntrinsic>(DebugUser->clone());
1441+
Cloned->replaceVariableLocationOp(0u, ExitValue);
1442+
Cloned->insertBefore(*Successor, Successor->getFirstNonPHIIt());
1443+
}
1444+
}
1445+
14041446
int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
14051447
ScalarEvolution *SE,
14061448
const TargetTransformInfo *TTI,
@@ -1542,6 +1584,10 @@ int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
15421584
(isa<PHINode>(Inst) || isa<LandingPadInst>(Inst)) ?
15431585
&*Inst->getParent()->getFirstInsertionPt() : Inst;
15441586
RewritePhiSet.emplace_back(PN, i, ExitValue, InsertPt, HighCost);
1587+
1588+
// Add debug values for the candidate PHINode incoming value.
1589+
if (BasicBlock *Successor = ExitBB->getSingleSuccessor())
1590+
addDebugValuesToIncomingValue(Successor, PN->getIncomingValue(i), PN);
15451591
}
15461592
}
15471593
}
@@ -1600,11 +1646,30 @@ int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
16001646
// Replace PN with ExitVal if that is legal and does not break LCSSA.
16011647
if (PN->getNumIncomingValues() == 1 &&
16021648
LI->replacementPreservesLCSSAForm(PN, ExitVal)) {
1649+
addDebugValuesToLoopVariable(PN->getParent(), ExitVal, PN);
16031650
PN->replaceAllUsesWith(ExitVal);
16041651
PN->eraseFromParent();
16051652
}
16061653
}
16071654

1655+
// If the loop can be deleted and there are no PHIs to be rewritten (there
1656+
// are no loop live-out values), record debug variables corresponding to the
1657+
// induction variable with their constant exit-values. Those values will be
1658+
// inserted by the 'deletion loop' logic.
1659+
if (LoopCanBeDel && RewritePhiSet.empty()) {
1660+
if (auto *IndVar = L->getInductionVariable(*SE)) {
1661+
const SCEV *PNSCEV = SE->getSCEVAtScope(IndVar, L->getParentLoop());
1662+
if (auto *Const = dyn_cast<SCEVConstant>(PNSCEV)) {
1663+
Value *FinalIVValue = Const->getValue();
1664+
if (L->getUniqueExitBlock()) {
1665+
SmallVector<DbgVariableIntrinsic *> DbgUsers;
1666+
findDbgUsers(DbgUsers, IndVar);
1667+
L->preserveDebugInductionVariableInfo(FinalIVValue, DbgUsers);
1668+
}
1669+
}
1670+
}
1671+
}
1672+
16081673
// The insertion point instruction may have been deleted; clear it out
16091674
// so that the rewriter doesn't trip over it later.
16101675
Rewriter.clearInsertPoint();
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
; RUN: opt -passes="loop(indvars)" \
2+
; RUN: --experimental-debuginfo-iterators=false -S -o - < %s | \
3+
; RUN: FileCheck --check-prefix=CHECK %s
4+
; RUN: opt -passes="loop(indvars,loop-deletion)" \
5+
; RUN: --experimental-debuginfo-iterators=false -S -o - < %s | \
6+
; RUN: FileCheck --check-prefix=CHECK %s
7+
8+
; Make sure that when we delete the loop, that the variable Index has
9+
; the 777 value.
10+
11+
; As this test case does fire the 'indvars' transformation, the debug values
12+
; are added to the 'for.end' exit block. No debug values are preserved by the
13+
; pass to be used by the 'loop-deletion' pass.
14+
15+
; CHECK: for.cond:
16+
; CHECK: call void @llvm.dbg.value(metadata i32 %[[SSA_INDEX_0:.+]], metadata ![[DBG:[0-9]+]], {{.*}}
17+
18+
; CHECK: for.extra:
19+
; CHECK: %[[SSA_CALL_0:.+]] = call noundef i32 @"?nop@@YAHH@Z"(i32 noundef %[[SSA_INDEX_0]]), {{.*}}
20+
; CHECK: br i1 %[[SSA_CMP_0:.+]], label %for.cond, label %if.else, {{.*}}
21+
22+
; CHECK: if.then:
23+
; CHECK: call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG]], {{.*}}
24+
; CHECK: call void @llvm.dbg.value(metadata i32 %[[SSA_VAR_1:.+]], metadata ![[VAR:[0-9]+]], {{.*}}
25+
; CHECK: br label %for.end, {{.*}}
26+
27+
; CHECK: if.else:
28+
; CHECK: call void @llvm.dbg.value(metadata i32 %[[SSA_VAR_2:.+]], metadata ![[VAR:[0-9]+]], {{.*}}
29+
; CHECK: br label %for.end, {{.*}}
30+
31+
; CHECK: for.end:
32+
; CHECK: call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG]], {{.*}}
33+
34+
; CHECK-DAG: ![[DBG]] = !DILocalVariable(name: "Index"{{.*}})
35+
; CHECK-DAG: ![[VAR]] = !DILocalVariable(name: "Var"{{.*}})
36+
37+
define dso_local noundef i32 @"?nop@@YAHH@Z"(i32 noundef %Param) !dbg !11 {
38+
entry:
39+
%Param.addr = alloca i32, align 4
40+
store i32 %Param, ptr %Param.addr, align 4
41+
call void @llvm.dbg.declare(metadata ptr %Param.addr, metadata !32, metadata !DIExpression()), !dbg !35
42+
ret i32 0, !dbg !36
43+
}
44+
45+
define dso_local void @_Z3barv() local_unnamed_addr #1 !dbg !12 {
46+
entry:
47+
call void @llvm.dbg.value(metadata i32 777, metadata !16, metadata !DIExpression()), !dbg !17
48+
call void @llvm.dbg.value(metadata i32 27, metadata !18, metadata !DIExpression()), !dbg !17
49+
call void @llvm.dbg.value(metadata i32 1, metadata !19, metadata !DIExpression()), !dbg !17
50+
call void @llvm.dbg.value(metadata i32 1, metadata !30, metadata !DIExpression()), !dbg !17
51+
br label %for.cond, !dbg !20
52+
53+
for.cond: ; preds = %for.cond, %entry
54+
%Index.0 = phi i32 [ 27, %entry ], [ %inc, %for.extra ], !dbg !17
55+
call void @llvm.dbg.value(metadata i32 %Index.0, metadata !18, metadata !DIExpression()), !dbg !17
56+
%cmp = icmp ult i32 %Index.0, 777, !dbg !21
57+
%inc = add nuw nsw i32 %Index.0, 1, !dbg !24
58+
call void @llvm.dbg.value(metadata i32 %inc, metadata !18, metadata !DIExpression()), !dbg !17
59+
br i1 %cmp, label %for.extra, label %if.then, !dbg !25, !llvm.loop !26
60+
61+
for.extra:
62+
%call.0 = call noundef i32 @"?nop@@YAHH@Z"(i32 noundef %Index.0), !dbg !21
63+
%cmp.0 = icmp ult i32 %Index.0, %call.0, !dbg !21
64+
br i1 %cmp.0, label %for.cond, label %if.else, !dbg !25, !llvm.loop !26
65+
66+
if.then: ; preds = %for.cond
67+
%Var.1 = add nsw i32 %Index.0, 1, !dbg !20
68+
call void @llvm.dbg.value(metadata i32 %Var.1, metadata !19, metadata !DIExpression()), !dbg !20
69+
br label %for.end, !dbg !20
70+
71+
if.else:
72+
%Var.2 = add nsw i32 %Index.0, 2, !dbg !20
73+
call void @llvm.dbg.value(metadata i32 %Var.2, metadata !19, metadata !DIExpression()), !dbg !20
74+
br label %for.end, !dbg !20
75+
76+
for.end: ; preds = %if.else, %if.then
77+
%Zeta.0 = phi i32 [ %Var.1, %if.then ], [ %Var.2, %if.else ], !dbg !20
78+
call void @llvm.dbg.value(metadata i32 %Zeta.0, metadata !30, metadata !DIExpression()), !dbg !20
79+
%Var.3 = add nsw i32 %Index.0, 1, !dbg !20
80+
call void @llvm.dbg.value(metadata i32 %Var.3, metadata !19, metadata !DIExpression()), !dbg !20
81+
%call = call noundef i32 @"?nop@@YAHH@Z"(i32 noundef %Index.0), !dbg !37
82+
ret void, !dbg !29
83+
}
84+
85+
declare void @llvm.dbg.value(metadata, metadata, metadata)
86+
declare void @llvm.dbg.declare(metadata, metadata, metadata)
87+
88+
!llvm.dbg.cu = !{!0}
89+
!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
90+
!llvm.ident = !{!9}
91+
92+
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
93+
!1 = !DIFile(filename: "test.cpp", directory: "")
94+
!2 = !{i32 7, !"Dwarf Version", i32 5}
95+
!3 = !{i32 2, !"Debug Info Version", i32 3}
96+
!4 = !{i32 1, !"wchar_size", i32 4}
97+
!5 = !{i32 8, !"PIC Level", i32 2}
98+
!6 = !{i32 7, !"PIE Level", i32 2}
99+
!7 = !{i32 7, !"uwtable", i32 2}
100+
!8 = !{i32 7, !"frame-pointer", i32 2}
101+
!9 = !{!"clang version 18.0.0"}
102+
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
103+
!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)
104+
!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)
105+
!13 = !DISubroutineType(types: !14)
106+
!14 = !{null}
107+
!15 = !{}
108+
!16 = !DILocalVariable(name: "End", scope: !12, file: !1, line: 6, type: !10)
109+
!17 = !DILocation(line: 0, scope: !12)
110+
!18 = !DILocalVariable(name: "Index", scope: !12, file: !1, line: 7, type: !10)
111+
!19 = !DILocalVariable(name: "Var", scope: !12, file: !1, line: 8, type: !10)
112+
!20 = !DILocation(line: 9, column: 3, scope: !12)
113+
!21 = !DILocation(line: 9, column: 16, scope: !22)
114+
!22 = distinct !DILexicalBlock(scope: !23, file: !1, line: 9, column: 3)
115+
!23 = distinct !DILexicalBlock(scope: !12, file: !1, line: 9, column: 3)
116+
!24 = !DILocation(line: 9, column: 23, scope: !22)
117+
!25 = !DILocation(line: 9, column: 3, scope: !23)
118+
!26 = distinct !{!26, !25, !27, !28}
119+
!27 = !DILocation(line: 10, column: 5, scope: !23)
120+
!28 = !{!"llvm.loop.mustprogress"}
121+
!29 = !DILocation(line: 12, column: 1, scope: !12)
122+
!30 = !DILocalVariable(name: "Zeta", scope: !12, file: !1, line: 8, type: !10)
123+
!31 = !{!32}
124+
!32 = !DILocalVariable(name: "Param", arg: 1, scope: !11, file: !1, line: 1, type: !10)
125+
!33 = !DISubroutineType(types: !34)
126+
!34 = !{!10, !10}
127+
!35 = !DILocation(line: 1, scope: !11)
128+
!36 = !DILocation(line: 2, scope: !11)
129+
!37 = !DILocation(line: 20, scope: !12)

0 commit comments

Comments
 (0)