Skip to content

Commit 7cd826a

Browse files
committed
[LoopUnroll][DebugInfo] Don't add metadata to unrolled remainder loop
Debug information can be, and was, corrupted when the runtime remainder loop was fully unrolled. This is because a !null node can be created instead of a unique one describing the loop. In this case, the original node gets incorrectly updated with the NewLoopID metadata. In the case when the remainder loop is going to be quickly fully unrolled, there isn't the need to add loop metadata for it anyway. Differential Revision: https://reviews.llvm.org/D37338 llvm-svn: 312471
1 parent 69e2278 commit 7cd826a

File tree

3 files changed

+122
-9
lines changed

3 files changed

+122
-9
lines changed

llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,12 @@ CloneLoopBlocks(Loop *L, Value *NewIter, const bool CreateRemainderLoop,
394394
if (CreateRemainderLoop) {
395395
Loop *NewLoop = NewLoops[L];
396396
assert(NewLoop && "L should have been cloned");
397+
398+
// Only add loop metadata if the loop is not going to be completely
399+
// unrolled.
400+
if (UnrollRemainder)
401+
return NewLoop;
402+
397403
// Add unroll disable metadata to disable future unrolling for this loop.
398404
SmallVector<Metadata *, 4> MDs;
399405
// Reserve first location for self reference to the LoopID metadata node.
@@ -414,13 +420,11 @@ CloneLoopBlocks(Loop *L, Value *NewIter, const bool CreateRemainderLoop,
414420
}
415421

416422
LLVMContext &Context = NewLoop->getHeader()->getContext();
417-
if (!UnrollRemainder) {
418-
SmallVector<Metadata *, 1> DisableOperands;
419-
DisableOperands.push_back(MDString::get(Context,
420-
"llvm.loop.unroll.disable"));
421-
MDNode *DisableNode = MDNode::get(Context, DisableOperands);
422-
MDs.push_back(DisableNode);
423-
}
423+
SmallVector<Metadata *, 1> DisableOperands;
424+
DisableOperands.push_back(MDString::get(Context,
425+
"llvm.loop.unroll.disable"));
426+
MDNode *DisableNode = MDNode::get(Context, DisableOperands);
427+
MDs.push_back(DisableNode);
424428

425429
MDNode *NewLoopID = MDNode::get(Context, MDs);
426430
// Set operand 0 to refer to the loop id itself.
@@ -536,6 +540,8 @@ bool llvm::UnrollRuntimeLoopRemainder(Loop *L, unsigned Count,
536540
bool PreserveLCSSA) {
537541
DEBUG(dbgs() << "Trying runtime unrolling on Loop: \n");
538542
DEBUG(L->dump());
543+
DEBUG(UseEpilogRemainder ? dbgs() << "Using epilog remainder.\n" :
544+
dbgs() << "Using prolog remainder.\n");
539545

540546
// Make sure the loop is in canonical form.
541547
if (!L->isLoopSimplifyForm()) {
@@ -892,6 +898,7 @@ bool llvm::UnrollRuntimeLoopRemainder(Loop *L, unsigned Count,
892898
}
893899

894900
if (remainderLoop && UnrollRemainder) {
901+
DEBUG(dbgs() << "Unrolling remainder loop\n");
895902
UnrollLoop(remainderLoop, /*Count*/Count - 1, /*TripCount*/Count - 1,
896903
/*Force*/false, /*AllowRuntime*/false,
897904
/*AllowExpensiveTripCount*/false, /*PreserveCondBr*/true,
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
; RUN: opt -loop-unroll -unroll-runtime -unroll-allow-remainder -unroll-count=4 -unroll-remainder -S %s -o - | FileCheck %s
2+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
3+
target triple = "x86_64-unknown-linux-gnu"
4+
5+
@b = common local_unnamed_addr global i32 0, align 4, !dbg !0
6+
@a = common local_unnamed_addr global i32* null, align 8, !dbg !6
7+
8+
; Test that loop remainder unrolling doesn't corrupt debuginfo. This example
9+
; used to cause an assert, but also test that the unrolled backwards branches
10+
; have the same DILocation.
11+
12+
; CHECK-LABEL: func_c
13+
; CHECK-LABEL: for.body.lr.ph:
14+
; CHECK: br i1 %[[CMP0:.*]], label %[[PRE:.*]], label %for.body.prol.loopexit, !dbg !24
15+
; CHECK-LABEL: for.body:
16+
; CHECK: br i1 %[[CMP1:.*]], label %[[CRIT_EDGE:.*]], label %for.body, !dbg !24, !llvm.loop !30
17+
; CHECK-LABEL: for.cond.for.end_crit_edge:
18+
; CHECK: br label %for.end, !dbg !24
19+
; CHECK-LABEL: for.body.prol.1:
20+
; CHECK: br i1 %[[CMP2:.*]], label %for.body.prol.2, label %[[EXIT:.*]], !dbg !24
21+
; CHECK-LABEL: for.body.prol.2:
22+
define i32 @func_c() local_unnamed_addr #0 !dbg !14 {
23+
entry:
24+
%.pr = load i32, i32* @b, align 4, !dbg !17, !tbaa !20
25+
%tobool1 = icmp eq i32 %.pr, 0, !dbg !24
26+
br i1 %tobool1, label %for.end, label %for.body.lr.ph, !dbg !24
27+
28+
for.body.lr.ph:
29+
%a.promoted = load i32*, i32** @a, align 8, !dbg !25, !tbaa !26
30+
%0 = sub i32 -2, %.pr, !dbg !24
31+
%1 = and i32 %0, -2, !dbg !24
32+
%2 = add i32 %.pr, %1, !dbg !24
33+
br label %for.body, !dbg !24
34+
35+
for.body:
36+
%3 = phi i32* [ %a.promoted, %for.body.lr.ph ], [ %6, %for.body ], !dbg !28
37+
%4 = phi i32 [ %.pr, %for.body.lr.ph ], [ %add, %for.body ]
38+
%arrayidx = getelementptr inbounds i32, i32* %3, i64 1, !dbg !28
39+
%5 = load i32, i32* %arrayidx, align 4, !dbg !28, !tbaa !20
40+
%conv = sext i32 %5 to i64, !dbg !28
41+
%6 = inttoptr i64 %conv to i32*, !dbg !28
42+
%add = add nsw i32 %4, 2, !dbg !29
43+
%tobool = icmp eq i32 %add, 0, !dbg !24
44+
br i1 %tobool, label %for.cond.for.end_crit_edge, label %for.body, !dbg !24, !llvm.loop !30
45+
46+
for.cond.for.end_crit_edge:
47+
%7 = add i32 %2, 2, !dbg !24
48+
store i32* %6, i32** @a, align 8, !dbg !25, !tbaa !26
49+
store i32 %7, i32* @b, align 4, !dbg !32, !tbaa !20
50+
br label %for.end, !dbg !24
51+
52+
for.end:
53+
ret i32 undef, !dbg !33
54+
}
55+
56+
; CHECK-LABEL: func_d
57+
define void @func_d() local_unnamed_addr #1 !dbg !34 {
58+
entry:
59+
ret void, !dbg !37
60+
}
61+
62+
attributes #0 = { norecurse nounwind uwtable }
63+
attributes #0 = { norecurse nounwind readnone uwtable }
64+
65+
!llvm.dbg.cu = !{!2}
66+
!llvm.module.flags = !{!10, !11, !12}
67+
!llvm.ident = !{!13}
68+
69+
!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
70+
!1 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 2, type: !9, isLocal: false, isDefinition: true)
71+
!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 6.0.0 (http://llvm.org/git/clang.git 044091b728654e62444a7ea10e6efb489c705bed) (http://llvm.org/git/llvm.git 1c7b55afdb1c5791e0557d9e32e2dd07c7acb2b0)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5)
72+
!3 = !DIFile(filename: "loop.c", directory: "/work/projects/src/tests/unroll-debug-info")
73+
!4 = !{}
74+
!5 = !{!6, !0}
75+
!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression())
76+
!7 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true)
77+
!8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64)
78+
!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
79+
!10 = !{i32 2, !"Dwarf Version", i32 4}
80+
!11 = !{i32 2, !"Debug Info Version", i32 3}
81+
!12 = !{i32 1, !"wchar_size", i32 4}
82+
!13 = !{!"clang version 6.0.0 (http://llvm.org/git/clang.git 044091b728654e62444a7ea10e6efb489c705bed) (http://llvm.org/git/llvm.git 1c7b55afdb1c5791e0557d9e32e2dd07c7acb2b0)"}
83+
!14 = distinct !DISubprogram(name: "c", scope: !3, file: !3, line: 3, type: !15, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !2, variables: !4)
84+
!15 = !DISubroutineType(types: !16)
85+
!16 = !{!9}
86+
!17 = !DILocation(line: 4, column: 12, scope: !18)
87+
!18 = distinct !DILexicalBlock(scope: !19, file: !3, line: 4, column: 5)
88+
!19 = distinct !DILexicalBlock(scope: !14, file: !3, line: 4, column: 5)
89+
!20 = !{!21, !21, i64 0}
90+
!21 = !{!"int", !22, i64 0}
91+
!22 = !{!"omnipotent char", !23, i64 0}
92+
!23 = !{!"Simple C/C++ TBAA"}
93+
!24 = !DILocation(line: 4, column: 5, scope: !19)
94+
!25 = !DILocation(line: 5, column: 13, scope: !18)
95+
!26 = !{!27, !27, i64 0}
96+
!27 = !{!"any pointer", !22, i64 0}
97+
!28 = !DILocation(line: 5, column: 15, scope: !18)
98+
!29 = !DILocation(line: 4, column: 21, scope: !18)
99+
!30 = distinct !{!30, !24, !31}
100+
!31 = !DILocation(line: 5, column: 18, scope: !19)
101+
!32 = !DILocation(line: 4, column: 17, scope: !18)
102+
!33 = !DILocation(line: 6, column: 1, scope: !14)
103+
!34 = distinct !DISubprogram(name: "d", scope: !3, file: !3, line: 7, type: !35, isLocal: false, isDefinition: true, scopeLine: 7, isOptimized: true, unit: !2, variables: !4)
104+
!35 = !DISubroutineType(types: !36)
105+
!36 = !{null}
106+
!37 = !DILocation(line: 7, column: 11, scope: !34)

llvm/test/Transforms/LoopUnroll/runtime-unroll-remainder.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ for.cond.cleanup:
3333

3434
; CHECK: [[EPIL_PEEL0]]:
3535
; CHECK: [[PEEL_CMP0:%[a-z.0-9]+]] = icmp eq i64 %xtraiter, 1
36-
; CHECK: br i1 [[PEEL_CMP0]], label %[[EPIL_EXIT:.*]], label %[[EPIL_PEEL1:.*]],
36+
; CHECK: br i1 [[PEEL_CMP0]], label %[[EPIL_EXIT:.*]], label %[[EPIL_PEEL1:.*]]
3737

3838
; CHECK: [[EPIL_EXIT]]:
3939
; CHECK: br label %[[EXIT]]
@@ -54,7 +54,7 @@ for.cond.cleanup:
5454

5555
; CHECK: [[EPIL_PEEL1]]:
5656
; CHECK: [[PEEL_CMP1:%[a-z.0-9]+]] = icmp eq i64 %xtraiter, 2
57-
; CHECK: br i1 [[PEEL_CMP1]], label %[[EPIL_EXIT]], label %[[EPIL_PEEL2:.*]],
57+
; CHECK: br i1 [[PEEL_CMP1]], label %[[EPIL_EXIT]], label %[[EPIL_PEEL2:.*]]
5858

5959
; CHECK: [[EPIL_PEEL2]]:
6060
; CHECK: br label %[[EXIT]]

0 commit comments

Comments
 (0)