xref: /llvm-project/llvm/test/Transforms/SimplifyCFG/preserve-llvm-loop-metadata.ll (revision fa9cef50b1afc203b6b653396f9e775862c26e68)
1; RUN: opt -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -keep-loops=false -S < %s | FileCheck %s
2; RUN: opt -passes='simplifycfg<no-keep-loops>' -S < %s | FileCheck %s
3
4define void @test1(i32 %n) #0 {
5entry:
6  %n.addr = alloca i32, align 4
7  %count = alloca i32, align 4
8  store i32 %n, ptr %n.addr, align 4
9  store i32 0, ptr %count, align 4
10  br label %while.cond
11
12while.cond:                                       ; preds = %if.end, %entry
13  %0 = load i32, ptr %count, align 4
14  %1 = load i32, ptr %n.addr, align 4
15  %cmp = icmp ule i32 %0, %1
16  br i1 %cmp, label %while.body, label %while.end
17
18while.body:                                       ; preds = %while.cond
19  %2 = load i32, ptr %count, align 4
20  %rem = urem i32 %2, 2
21  %cmp1 = icmp eq i32 %rem, 0
22  br i1 %cmp1, label %if.then, label %if.else
23
24if.then:                                          ; preds = %while.body
25  %3 = load i32, ptr %count, align 4
26  %add = add i32 %3, 1
27  store i32 %add, ptr %count, align 4
28  br label %if.end
29
30; CHECK: if.then:
31; CHECK:  br label %while.cond, !llvm.loop !1
32
33if.else:                                          ; preds = %while.body
34  %4 = load i32, ptr %count, align 4
35  %add2 = add i32 %4, 2
36  store i32 %add2, ptr %count, align 4
37  br label %if.end
38
39; CHECK: if.else:
40; CHECK:  br label %while.cond, !llvm.loop !1
41
42if.end:                                           ; preds = %if.else, %if.then
43  br label %while.cond, !llvm.loop !1
44
45while.end:                                        ; preds = %while.cond
46  ret void
47}
48
49; Test that empty loop latch `while.cond.loopexit` will not be folded into its successor if its
50; predecessor blocks are also loop latches.
51;
52; The test case is constructed based on the following C++ code.
53; While the C++ code itself might have the inner-loop unrolled (e.g., with -O3),
54; the loss of inner-loop unroll metadata is a bug.
55; Under some optimization pipelines (e.g., FullLoopUnroll pass is skipped in ThinLTO prelink stage),
56; and in real-world C++ code (e.g., with larger loop body), failing to
57; preserve loop unroll metadata could cause missed loop unroll.
58;
59; constexpr int kUnroll = 5;
60; int sum(int a, int b, int step, const int remainder, int* input) {
61;    int i = a, j = b;
62;    int sum = 0;
63;    while(j - i > remainder) {
64;        i += step;
65;        #pragma unroll
66;        for (int k = 0; k < kUnroll; k++) {
67;           asm volatile ("add %w0, %w1\n" : "=r"(sum) : "r"(input[k + i]):"cc");
68;        }
69;    }
70;    return sum;
71; }
72define i32 @test2(i32 %a, i32 %b, i32 %step, i32 %remainder, ptr %input) {
73entry:
74  br label %while.cond
75
76while.cond.loopexit:                              ; preds = %for.body
77  br label %while.cond, !llvm.loop !3
78
79while.cond:                                       ; preds = %while.cond.loopexit, %entry
80  %i.0 = phi i32 [ %a, %entry ], [ %add, %while.cond.loopexit ]
81  %sum.0 = phi i32 [ 0, %entry ], [ %1, %while.cond.loopexit ]
82  %sub = sub nsw i32 %b, %i.0
83  %cmp = icmp sgt i32 %sub, %remainder
84  br i1 %cmp, label %while.body, label %while.end
85
86while.body:                                       ; preds = %while.cond
87  %add = add nsw i32 %i.0, %step
88  br label %for.body
89
90for.body:                                         ; preds = %while.body, %for.body
91  %k.07 = phi i32 [ 0, %while.body ], [ %inc, %for.body ]
92  %add2 = add nsw i32 %k.07, %add
93  %idxprom = sext i32 %add2 to i64
94  %arrayidx = getelementptr inbounds i32, ptr %input, i64 %idxprom
95  %0 = load i32, ptr %arrayidx, align 4
96  %1 = tail call i32 asm sideeffect "add ${0:w}, ${1:w}\0A", "=r,r,~{cc}"(i32 %0)
97  %inc = add nuw nsw i32 %k.07, 1
98  %cmp1 = icmp ult i32 %inc, 5
99  br i1 %cmp1, label %for.body, label %while.cond.loopexit, !llvm.loop !5
100
101while.end:                                        ; preds = %while.cond
102  %sum.0.lcssa = phi i32 [ %sum.0, %while.cond ]
103  ret i32 %sum.0.lcssa
104}
105
106; Test that the condition tested above does not trigger when the loop metadata consists only of debug locations,
107; i.e.the empty loop latch `while.cond.loopexit` *will* be folded into its successor if its
108; predecessor blocks are also loop latches and any loop metadata attached to it consists of debug information.
109;
110define i32 @test3(i32 %a, i32 %b, i32 %step, i32 %remainder, ptr %input) !dbg !7 {
111entry:
112  br label %while.cond
113
114;CHECK-LABEL: @test3(
115;CHECK-NOT: while.cond.loopexit
116while.cond.loopexit:                              ; preds = %for.body
117  br label %while.cond, !llvm.loop !10
118
119while.cond:                                       ; preds = %while.cond.loopexit, %entry
120  %i.0 = phi i32 [ %a, %entry ], [ %add, %while.cond.loopexit ]
121  %sum.0 = phi i32 [ 0, %entry ], [ %1, %while.cond.loopexit ]
122  %sub = sub nsw i32 %b, %i.0
123  %cmp = icmp sgt i32 %sub, %remainder
124  br i1 %cmp, label %while.body, label %while.end
125
126while.body:                                       ; preds = %while.cond
127  %add = add nsw i32 %i.0, %step
128  br label %for.body
129
130for.body:                                         ; preds = %while.body, %for.body
131  %k.07 = phi i32 [ 0, %while.body ], [ %inc, %for.body ]
132  %add2 = add nsw i32 %k.07, %add
133  %idxprom = sext i32 %add2 to i64
134  %arrayidx = getelementptr inbounds i32, ptr %input, i64 %idxprom
135  %0 = load i32, ptr %arrayidx, align 4
136  %1 = tail call i32 asm sideeffect "add ${0:w}, ${1:w}\0A", "=r,r,~{cc}"(i32 %0)
137  %inc = add nuw nsw i32 %k.07, 1
138  %cmp1 = icmp ult i32 %inc, 5
139  br i1 %cmp1, label %for.body, label %while.cond.loopexit, !llvm.loop !5
140
141while.end:                                        ; preds = %while.cond
142  %sum.0.lcssa = phi i32 [ %sum.0, %while.cond ]
143  ret i32 %sum.0.lcssa
144}
145
146!llvm.module.flags = !{!0}
147
148!0 = !{i32 2, !"Debug Info Version", i32 3}
149!1 = distinct !{!1, !2}
150!2 = !{!"llvm.loop.distribute.enable", i1 true}
151!3 = distinct !{!3, !4}
152!4 = !{!"llvm.loop.mustprogress"}
153!5 = distinct !{!5, !4, !6}
154!6 = !{!"llvm.loop.unroll.enable"}
155!7 = distinct !DISubprogram(name: "test3", scope: !8, file: !8, spFlags: DISPFlagDefinition, unit: !9)
156!8 = !DIFile(filename: "preserve-llvm-loop-metadata.ll", directory: "/")
157!9 = distinct !DICompileUnit(language: DW_LANG_C99, file: !8, isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug)
158!10 = distinct !{!10, !11, !13}
159!11 = !DILocation(line: 8, column: 4, scope: !12)
160!12 = distinct !DILexicalBlock(scope: !7, file: !8, line: 8, column: 2)
161!13 = !DILocation(line: 9, column: 23, scope: !12)
162
163; CHECK: !1 = distinct !{!1, !2}
164; CHECK: !2 = !{!"llvm.loop.distribute.enable", i1 true}
165; CHECK: !3 = distinct !{!3, !4}
166; CHECK: !4 = !{!"llvm.loop.mustprogress"}
167; CHECK: !5 = distinct !{!5, !4, !6}
168; CHECK: !6 = !{!"llvm.loop.unroll.enable"}
169; CHECK-NOT: !10 = distinct !{!10, !11, !13}
170