-
Notifications
You must be signed in to change notification settings - Fork 12.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[indvars] Missing variables at Og: #69920
Conversation
@llvm/pr-subscribers-llvm-support @llvm/pr-subscribers-debuginfo Author: Carlos Alberto Enciso (CarlosAlbertoEnciso) Changeshttps://bugs.llvm.org/show_bug.cgi?id=51735 In the given test case:
Missing local variable Full diff: https://github.com/llvm/llvm-project/pull/69920.diff 3 Files Affected:
diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
index 41c4d6236173472..0e20b5e62040374 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 000000000000000..de9a74522095659
--- /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 000000000000000..b9bdc8ca1b6fb09
--- /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)
|
3a32bec
to
276fcc7
Compare
@nikic Thanks for your feedback.
|
|
||
// 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)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still the wrong place to do this. You are updating just a single "induction variable" here, while the code can rewrite multiple, and can also use different exit values for different blocks. This adjustment should be above in the // Transformation.
loop, which has all the induction phis and their replacement values.
if (PHINode *IndVar = L->getInductionVariable(*SE)) { | ||
const SCEV *IndVarSCEV = SE->getSCEVAtScope(IndVar, L->getParentLoop()); | ||
if (isa<SCEVConstant>(IndVarSCEV)) { | ||
Value *FinalIVValue = cast<SCEVConstant>(IndVarSCEV)->getValue(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that you should not use an isa<> test followed by a cast<>, for that use the dyn_cast<> operator.
https://llvm.org/docs/ProgrammersManual.html#the-isa-cast-and-dyn-cast-templates
I think this would be easier to follow with an early exit on the result of the dyn cast: https://llvm.org/docs/CodingStandards.html#use-early-exits-and-continue-to-simplify-code
findDbgUsers(DbgUsers, IndVar); | ||
for (auto &DebugUser : DbgUsers) { | ||
auto *Cloned = cast<DbgVariableIntrinsic>(DebugUser->clone()); | ||
Cloned->replaceVariableLocationOp(static_cast<unsigned>(0), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
0u
SmallVector<DbgVariableIntrinsic *> DbgUsers; | ||
SmallVector<DbgVariableIntrinsic *> DbgUsersCloned; | ||
findDbgUsers(DbgUsers, IndVar); | ||
for (auto &DebugUser : DbgUsers) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we don't need a reference to a pointer here (we are not modifying the pointer), we can use auto *
to express this intent
SmallVector<BasicBlock *> ExitBlocks; | ||
L->getExitBlocks(ExitBlocks); | ||
for (BasicBlock *Exit : ExitBlocks) | ||
for (auto &DebugUser : DbgUsersCloned) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
similarly here auto *
; 15 bar(); | ||
; 16 } | ||
|
||
; CHECK: for.cond: {{.*}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need this {{.*}}
? (and in the other BB labels)
; 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]+]], {{.*}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if I understand this test correctly, all of these dbg.values are for the variable Index
, right? I think it's important that we label the first occurrence of it and check that all three of these intrinsics are referring to it (right now we allow any metadata there)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that we are redefining what ![[DBG]]
is in each of these CHECKs
|
||
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this and the third intrinsic relevant for the test? (i.e. the intrinsics that don't target !23 = Index
; CHECK: call void @llvm.dbg.value(metadata i32 777, metadata ![[DBG:[0-9]+]], {{.*}} | ||
; CHECK-DAG: ![[DBG]] = !DILocalVariable(name: "Index"{{.*}}) | ||
|
||
define dso_local void @_Z3barv() local_unnamed_addr #1 !dbg !15 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you elaborate on how these tests differ from each other? I couldn't tell by comparing the two
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(IIRC, the difference is that there are multiple exit blocks, to stimulate more of the paths through the code-changes).
276fcc7
to
9cad349
Compare
I am sorry for my delay in addressing the comments from the reviewers, but I was on PTO.
|
// get updated, which is fine as that is the existing behaviour. | ||
if (DebugUser->hasArgList()) | ||
continue; | ||
for (BasicBlock *Exit : ExitBlocks) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ExitValue is specific to one exit block. Why are you updating all of them here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reworked the code to take into account that point. Reworked in new patch.
@@ -1482,6 +1513,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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this code needed in addition to the addDebugValuesToLoopVariable() below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That code creates a debug value in the exit block if any of the incoming values for the PHI Node being replaced is the induction variable. Reworked in new patch.
74d48ef
to
88f7d8c
Compare
Uploaded a new patch that addresses @nikic feedback. |
✅ With the latest revision this PR passed the C/C++ code formatter. |
88f7d8c
to
0270560
Compare
Uploaded patch fixing the C/C++ code formatter, clang-format found issues. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the change adding the "ExitBlock" field to the RewritePhi struct -- as far as understand it, the PHI being rewritten is always going to be in that exit block. Perhaps we could not store it in the struct and instead recover the exit block by calling getParent()
on the PHI when necessary, instead? (This avoids two storing two pieces of information and having to think about whether they're in sync or not).
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reckon you want to say "rewrite debug variables" or similar, just to signal to the reader that these aren't for SSA variables which might have a functional effect on the program.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed.
// 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"for the given induction..."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed.
Good point. Removed the added field. |
https://bugs.llvm.org/show_bug.cgi?id=51735 llvm#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.
04fa787
to
0427224
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Largely looks good, some comments inline.
SmallVector<WeakVH> &DbgUsers = L->getDebugInductionVariableDebugUsers(); | ||
for (WeakVH &DebugUser : DbgUsers) | ||
if (DebugUser) | ||
dyn_cast<DbgVariableIntrinsic>(DebugUser)->replaceVariableLocationOp( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dyn_cast<DbgVariableIntrinsic>(DebugUser)->replaceVariableLocationOp( | |
cast<DbgVariableIntrinsic>(DebugUser)->replaceVariableLocationOp( |
This should just be a normal cast
- the idea of dyn_cast
is that it can return nullptr
if the cast is unsuccessful, unlike cast
which just asserts; if you aren't checking the result for nullptr
, then there's no value in using dyn_cast
over cast
. I think in this case, you just want cast
, since the check above already verifies that the value has not been deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the additional information on dyn_cast
. Changed to cast
.
; PRE-CHECK: br label %for.cond | ||
|
||
; PRE-CHECK: for.end: | ||
; PRE-CHECK-NOT: call void @llvm.dbg.value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be skipped since there's an implicit-check-not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
|
||
; Only the 'indvars' pass is executed. | ||
; PRE-CHECK: for.cond: | ||
; PRE-CHECK: call void @llvm.dbg.value(metadata i32 %Var.0, metadata ![[DBG]], {{.*}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This and a lot of the other check lines may fail in a build without assertions enabled, as the SSA values won't necessarily be printed with the same names (they may become numbered values, e.g. %5
, %6
, etc). Usually the way to test these would then be to use capture variables for them, e.g. i32 %[[SSA_VAR0:.+]],
. This gets tedious if you have to use it for every variable, so I'd recommend removing the unrelated CHECK lines, which would be most of the lines that don't need to be tested for and don't produce a value that we want to check; or instead of removing them, you could cut out actual SSA values, i.e. you could just test for = icmp eq
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the additional information. Changed to use captured variables
.
continue; | ||
auto *Cloned = cast<DbgVariableIntrinsic>(DebugUser->clone()); | ||
Cloned->replaceVariableLocationOp(0u, PN); | ||
Cloned->insertBefore(Successor->getFirstNonPHI()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should fix this up for the new insert logic (same in the function below):
Cloned->insertBefore(Successor->getFirstNonPHI()); | |
Cloned->insertBefore(Successor, Successor->getFirstNonPHIIt()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to use new insert logic.
https://bugs.llvm.org/show_bug.cgi?id=51735 llvm#51077 Address @SLTozer comments. - Use captured variables for SSA values. - Use new insert logic calls. - Remove not required 'CHECK-NOT'.
@SLTozer Thanks for your comments. Updated the patch. |
One more part - you've captured the SSA values that are needed for the test, but for the SSA values you're not using you should still remove the actual names so that if the identifiers change (which can happen when building with assertions |
https://bugs.llvm.org/show_bug.cgi?id=51735 llvm#51077 Address @SLTozer comments. - Don't use any names for not used SSA values.
@SLTozer Thanks for the suggested changes when dealing with the not used SSA values. |
Any additional comments or suggestions? Thanks. |
Thanks to all reviewers for their comments. |
This introduces a layering violation. GenericLoopInfo in Support is not allowed to depend on IR. That's the point of the GenericXYZ implementations, they are IR-agnostic. Edit: Reverted in 91189af. |
// there are no PHIs to be rewritten. | ||
// For now, we only preserve single induction variables. | ||
Value *IndVarFinalValue = nullptr; | ||
SmallVector<WeakVH> IndVarDebugUsers; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it necessary for these to be members on the Loop object itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It also introduced some link errors. Reverting the patch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for reverting. I will look at that layering violation.
This reverts commit 739fa1c. This introduces a layering violation by using IR in Support headers.
https://bugs.llvm.org/show_bug.cgi?id=51735
#51077
In the given test case:
Missing local variable
Index
after loopInduction Variable Elimination
.When adding a breakpoint at line
11
, LLDB does not have informationon the variable. But it has info on
Var
andEnd
.