Bump version to 19.1.0-rc3
[llvm-project.git] / llvm / test / Transforms / LoopUnroll / unroll-loads-cse.ll
blobd4105254e531468659c3522d8dacda8b094981ec
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
2 ; RUN: opt -p loop-unroll -S %s | FileCheck %s
4 target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
6 define void @cse_matching_load_from_previous_unrolled_iteration(ptr %src, ptr noalias %dst, i64 %N) {
7 ; CHECK-LABEL: define void @cse_matching_load_from_previous_unrolled_iteration(
8 ; CHECK-SAME: ptr [[SRC:%.*]], ptr noalias [[DST:%.*]], i64 [[N:%.*]]) {
9 ; CHECK-NEXT:  entry:
10 ; CHECK-NEXT:    [[SRC_4:%.*]] = getelementptr i8, ptr [[SRC]], i64 4
11 ; CHECK-NEXT:    [[SRC_12:%.*]] = getelementptr i8, ptr [[SRC]], i64 12
12 ; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[N]], -1
13 ; CHECK-NEXT:    [[XTRAITER:%.*]] = and i64 [[N]], 1
14 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 1
15 ; CHECK-NEXT:    br i1 [[TMP1]], label [[EXIT_UNR_LCSSA:%.*]], label [[ENTRY_NEW:%.*]]
16 ; CHECK:       entry.new:
17 ; CHECK-NEXT:    [[UNROLL_ITER:%.*]] = sub i64 [[N]], [[XTRAITER]]
18 ; CHECK-NEXT:    br label [[LOOP:%.*]]
19 ; CHECK:       loop:
20 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY_NEW]] ], [ [[IV_NEXT_1:%.*]], [[LOOP]] ]
21 ; CHECK-NEXT:    [[NITER:%.*]] = phi i64 [ 0, [[ENTRY_NEW]] ], [ [[NITER_NEXT_1:%.*]], [[LOOP]] ]
22 ; CHECK-NEXT:    [[GEP_SRC_12:%.*]] = getelementptr i64, ptr [[SRC_12]], i64 [[IV]]
23 ; CHECK-NEXT:    [[L_12:%.*]] = load i64, ptr [[GEP_SRC_12]], align 8
24 ; CHECK-NEXT:    [[GEP_SRC_4:%.*]] = getelementptr i64, ptr [[SRC_4]], i64 [[IV]]
25 ; CHECK-NEXT:    [[L_4:%.*]] = load i64, ptr [[GEP_SRC_4]], align 8
26 ; CHECK-NEXT:    [[MUL:%.*]] = mul i64 [[L_12]], [[L_4]]
27 ; CHECK-NEXT:    [[GEP_DST:%.*]] = getelementptr i64, ptr [[DST]], i64 [[IV]]
28 ; CHECK-NEXT:    store i64 [[MUL]], ptr [[GEP_DST]], align 8
29 ; CHECK-NEXT:    [[IV_NEXT:%.*]] = add nuw nsw i64 [[IV]], 1
30 ; CHECK-NEXT:    [[GEP_SRC_12_1:%.*]] = getelementptr i64, ptr [[SRC_12]], i64 [[IV_NEXT]]
31 ; CHECK-NEXT:    [[L_12_1:%.*]] = load i64, ptr [[GEP_SRC_12_1]], align 8
32 ; CHECK-NEXT:    [[MUL_1:%.*]] = mul i64 [[L_12_1]], [[L_12]]
33 ; CHECK-NEXT:    [[GEP_DST_1:%.*]] = getelementptr i64, ptr [[DST]], i64 [[IV_NEXT]]
34 ; CHECK-NEXT:    store i64 [[MUL_1]], ptr [[GEP_DST_1]], align 8
35 ; CHECK-NEXT:    [[IV_NEXT_1]] = add nuw nsw i64 [[IV]], 2
36 ; CHECK-NEXT:    [[NITER_NEXT_1]] = add i64 [[NITER]], 2
37 ; CHECK-NEXT:    [[NITER_NCMP_1:%.*]] = icmp eq i64 [[NITER_NEXT_1]], [[UNROLL_ITER]]
38 ; CHECK-NEXT:    br i1 [[NITER_NCMP_1]], label [[EXIT_UNR_LCSSA_LOOPEXIT:%.*]], label [[LOOP]], !llvm.loop [[LOOP0:![0-9]+]]
39 ; CHECK:       exit.unr-lcssa.loopexit:
40 ; CHECK-NEXT:    [[IV_UNR_PH:%.*]] = phi i64 [ [[IV_NEXT_1]], [[LOOP]] ]
41 ; CHECK-NEXT:    br label [[EXIT_UNR_LCSSA]]
42 ; CHECK:       exit.unr-lcssa:
43 ; CHECK-NEXT:    [[IV_UNR:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_UNR_PH]], [[EXIT_UNR_LCSSA_LOOPEXIT]] ]
44 ; CHECK-NEXT:    [[LCMP_MOD:%.*]] = icmp ne i64 [[XTRAITER]], 0
45 ; CHECK-NEXT:    br i1 [[LCMP_MOD]], label [[LOOP_EPIL_PREHEADER:%.*]], label [[EXIT:%.*]]
46 ; CHECK:       loop.epil.preheader:
47 ; CHECK-NEXT:    br label [[LOOP_EPIL:%.*]]
48 ; CHECK:       loop.epil:
49 ; CHECK-NEXT:    [[GEP_SRC_12_EPIL:%.*]] = getelementptr i64, ptr [[SRC_12]], i64 [[IV_UNR]]
50 ; CHECK-NEXT:    [[L_12_EPIL:%.*]] = load i64, ptr [[GEP_SRC_12_EPIL]], align 8
51 ; CHECK-NEXT:    [[GEP_SRC_4_EPIL:%.*]] = getelementptr i64, ptr [[SRC_4]], i64 [[IV_UNR]]
52 ; CHECK-NEXT:    [[L_4_EPIL:%.*]] = load i64, ptr [[GEP_SRC_4_EPIL]], align 8
53 ; CHECK-NEXT:    [[MUL_EPIL:%.*]] = mul i64 [[L_12_EPIL]], [[L_4_EPIL]]
54 ; CHECK-NEXT:    [[GEP_DST_EPIL:%.*]] = getelementptr i64, ptr [[DST]], i64 [[IV_UNR]]
55 ; CHECK-NEXT:    store i64 [[MUL_EPIL]], ptr [[GEP_DST_EPIL]], align 8
56 ; CHECK-NEXT:    br label [[EXIT]]
57 ; CHECK:       exit:
58 ; CHECK-NEXT:    ret void
60 entry:
61   %src.4 = getelementptr i8, ptr %src, i64 4
62   %src.12 = getelementptr i8, ptr %src, i64 12
63   br label %loop
65 loop:
66   %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
67   %gep.src.12 = getelementptr i64, ptr %src.12, i64 %iv
68   %l.12 = load i64, ptr %gep.src.12, align 8
69   %gep.src.4 = getelementptr i64, ptr %src.4, i64 %iv
70   %l.4 = load i64, ptr %gep.src.4, align 8
71   %mul = mul i64 %l.12, %l.4
72   %gep.dst = getelementptr i64, ptr %dst, i64 %iv
73   store i64 %mul, ptr %gep.dst
74   %iv.next = add nuw nsw i64 %iv, 1
75   %c = icmp eq i64 %iv.next, %N
76   br i1 %c, label %exit, label %loop, !llvm.loop !1
78 exit:
79   ret void
82 define void @cse_different_load_types(ptr %src, ptr noalias %dst, i64 %N) {
83 ; CHECK-LABEL: define void @cse_different_load_types(
84 ; CHECK-SAME: ptr [[SRC:%.*]], ptr noalias [[DST:%.*]], i64 [[N:%.*]]) {
85 ; CHECK-NEXT:  entry:
86 ; CHECK-NEXT:    [[SRC_4:%.*]] = getelementptr i8, ptr [[SRC]], i64 4
87 ; CHECK-NEXT:    [[SRC_12:%.*]] = getelementptr i8, ptr [[SRC]], i64 12
88 ; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[N]], -1
89 ; CHECK-NEXT:    [[XTRAITER:%.*]] = and i64 [[N]], 1
90 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 1
91 ; CHECK-NEXT:    br i1 [[TMP1]], label [[EXIT_UNR_LCSSA:%.*]], label [[ENTRY_NEW:%.*]]
92 ; CHECK:       entry.new:
93 ; CHECK-NEXT:    [[UNROLL_ITER:%.*]] = sub i64 [[N]], [[XTRAITER]]
94 ; CHECK-NEXT:    br label [[LOOP:%.*]]
95 ; CHECK:       loop:
96 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY_NEW]] ], [ [[IV_NEXT_1:%.*]], [[LOOP]] ]
97 ; CHECK-NEXT:    [[NITER:%.*]] = phi i64 [ 0, [[ENTRY_NEW]] ], [ [[NITER_NEXT_1:%.*]], [[LOOP]] ]
98 ; CHECK-NEXT:    [[GEP_SRC_12:%.*]] = getelementptr i64, ptr [[SRC_12]], i64 [[IV]]
99 ; CHECK-NEXT:    [[L_12:%.*]] = load i32, ptr [[GEP_SRC_12]], align 8
100 ; CHECK-NEXT:    [[L_12_EXT:%.*]] = zext i32 [[L_12]] to i64
101 ; CHECK-NEXT:    [[GEP_SRC_4:%.*]] = getelementptr i64, ptr [[SRC_4]], i64 [[IV]]
102 ; CHECK-NEXT:    [[L_4:%.*]] = load i64, ptr [[GEP_SRC_4]], align 8
103 ; CHECK-NEXT:    [[MUL:%.*]] = mul i64 [[L_12_EXT]], [[L_4]]
104 ; CHECK-NEXT:    [[GEP_DST:%.*]] = getelementptr i64, ptr [[DST]], i64 [[IV]]
105 ; CHECK-NEXT:    store i64 [[MUL]], ptr [[GEP_DST]], align 8
106 ; CHECK-NEXT:    [[IV_NEXT:%.*]] = add nuw nsw i64 [[IV]], 1
107 ; CHECK-NEXT:    [[GEP_SRC_12_1:%.*]] = getelementptr i64, ptr [[SRC_12]], i64 [[IV_NEXT]]
108 ; CHECK-NEXT:    [[L_12_1:%.*]] = load i32, ptr [[GEP_SRC_12_1]], align 8
109 ; CHECK-NEXT:    [[L_12_EXT_1:%.*]] = zext i32 [[L_12_1]] to i64
110 ; CHECK-NEXT:    [[GEP_SRC_4_1:%.*]] = getelementptr i64, ptr [[SRC_4]], i64 [[IV_NEXT]]
111 ; CHECK-NEXT:    [[L_4_1:%.*]] = load i64, ptr [[GEP_SRC_4_1]], align 8
112 ; CHECK-NEXT:    [[MUL_1:%.*]] = mul i64 [[L_12_EXT_1]], [[L_4_1]]
113 ; CHECK-NEXT:    [[GEP_DST_1:%.*]] = getelementptr i64, ptr [[DST]], i64 [[IV_NEXT]]
114 ; CHECK-NEXT:    store i64 [[MUL_1]], ptr [[GEP_DST_1]], align 8
115 ; CHECK-NEXT:    [[IV_NEXT_1]] = add nuw nsw i64 [[IV]], 2
116 ; CHECK-NEXT:    [[NITER_NEXT_1]] = add i64 [[NITER]], 2
117 ; CHECK-NEXT:    [[NITER_NCMP_1:%.*]] = icmp eq i64 [[NITER_NEXT_1]], [[UNROLL_ITER]]
118 ; CHECK-NEXT:    br i1 [[NITER_NCMP_1]], label [[EXIT_UNR_LCSSA_LOOPEXIT:%.*]], label [[LOOP]], !llvm.loop [[LOOP3:![0-9]+]]
119 ; CHECK:       exit.unr-lcssa.loopexit:
120 ; CHECK-NEXT:    [[IV_UNR_PH:%.*]] = phi i64 [ [[IV_NEXT_1]], [[LOOP]] ]
121 ; CHECK-NEXT:    br label [[EXIT_UNR_LCSSA]]
122 ; CHECK:       exit.unr-lcssa:
123 ; CHECK-NEXT:    [[IV_UNR:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_UNR_PH]], [[EXIT_UNR_LCSSA_LOOPEXIT]] ]
124 ; CHECK-NEXT:    [[LCMP_MOD:%.*]] = icmp ne i64 [[XTRAITER]], 0
125 ; CHECK-NEXT:    br i1 [[LCMP_MOD]], label [[LOOP_EPIL_PREHEADER:%.*]], label [[EXIT:%.*]]
126 ; CHECK:       loop.epil.preheader:
127 ; CHECK-NEXT:    br label [[LOOP_EPIL:%.*]]
128 ; CHECK:       loop.epil:
129 ; CHECK-NEXT:    [[GEP_SRC_12_EPIL:%.*]] = getelementptr i64, ptr [[SRC_12]], i64 [[IV_UNR]]
130 ; CHECK-NEXT:    [[L_12_EPIL:%.*]] = load i32, ptr [[GEP_SRC_12_EPIL]], align 8
131 ; CHECK-NEXT:    [[L_12_EXT_EPIL:%.*]] = zext i32 [[L_12_EPIL]] to i64
132 ; CHECK-NEXT:    [[GEP_SRC_4_EPIL:%.*]] = getelementptr i64, ptr [[SRC_4]], i64 [[IV_UNR]]
133 ; CHECK-NEXT:    [[L_4_EPIL:%.*]] = load i64, ptr [[GEP_SRC_4_EPIL]], align 8
134 ; CHECK-NEXT:    [[MUL_EPIL:%.*]] = mul i64 [[L_12_EXT_EPIL]], [[L_4_EPIL]]
135 ; CHECK-NEXT:    [[GEP_DST_EPIL:%.*]] = getelementptr i64, ptr [[DST]], i64 [[IV_UNR]]
136 ; CHECK-NEXT:    store i64 [[MUL_EPIL]], ptr [[GEP_DST_EPIL]], align 8
137 ; CHECK-NEXT:    br label [[EXIT]]
138 ; CHECK:       exit:
139 ; CHECK-NEXT:    ret void
141 entry:
142   %src.4 = getelementptr i8, ptr %src, i64 4
143   %src.12 = getelementptr i8, ptr %src, i64 12
144   br label %loop
146 loop:
147   %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
148   %gep.src.12 = getelementptr i64, ptr %src.12, i64 %iv
149   %l.12 = load i32, ptr %gep.src.12, align 8
150   %l.12.ext = zext i32 %l.12 to i64
151   %gep.src.4 = getelementptr i64, ptr %src.4, i64 %iv
152   %l.4 = load i64, ptr %gep.src.4, align 8
153   %mul = mul i64 %l.12.ext, %l.4
154   %gep.dst = getelementptr i64, ptr %dst, i64 %iv
155   store i64 %mul, ptr %gep.dst
156   %iv.next = add nuw nsw i64 %iv, 1
157   %c = icmp eq i64 %iv.next, %N
158   br i1 %c, label %exit, label %loop, !llvm.loop !1
160 exit:
161   ret void
164 define void @cse_volatile_loads(ptr %src, ptr noalias %dst, i64 %N) {
165 ; CHECK-LABEL: define void @cse_volatile_loads(
166 ; CHECK-SAME: ptr [[SRC:%.*]], ptr noalias [[DST:%.*]], i64 [[N:%.*]]) {
167 ; CHECK-NEXT:  entry:
168 ; CHECK-NEXT:    [[SRC_4:%.*]] = getelementptr i8, ptr [[SRC]], i64 4
169 ; CHECK-NEXT:    [[SRC_12:%.*]] = getelementptr i8, ptr [[SRC]], i64 12
170 ; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[N]], -1
171 ; CHECK-NEXT:    [[XTRAITER:%.*]] = and i64 [[N]], 1
172 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 1
173 ; CHECK-NEXT:    br i1 [[TMP1]], label [[EXIT_UNR_LCSSA:%.*]], label [[ENTRY_NEW:%.*]]
174 ; CHECK:       entry.new:
175 ; CHECK-NEXT:    [[UNROLL_ITER:%.*]] = sub i64 [[N]], [[XTRAITER]]
176 ; CHECK-NEXT:    br label [[LOOP:%.*]]
177 ; CHECK:       loop:
178 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY_NEW]] ], [ [[IV_NEXT_1:%.*]], [[LOOP]] ]
179 ; CHECK-NEXT:    [[NITER:%.*]] = phi i64 [ 0, [[ENTRY_NEW]] ], [ [[NITER_NEXT_1:%.*]], [[LOOP]] ]
180 ; CHECK-NEXT:    [[GEP_SRC_12:%.*]] = getelementptr i64, ptr [[SRC_12]], i64 [[IV]]
181 ; CHECK-NEXT:    [[L_12:%.*]] = load i64, ptr [[GEP_SRC_12]], align 8
182 ; CHECK-NEXT:    [[GEP_SRC_4:%.*]] = getelementptr i64, ptr [[SRC_4]], i64 [[IV]]
183 ; CHECK-NEXT:    [[L_4:%.*]] = load volatile i64, ptr [[GEP_SRC_4]], align 8
184 ; CHECK-NEXT:    [[MUL:%.*]] = mul i64 [[L_12]], [[L_4]]
185 ; CHECK-NEXT:    [[GEP_DST:%.*]] = getelementptr i64, ptr [[DST]], i64 [[IV]]
186 ; CHECK-NEXT:    store i64 [[MUL]], ptr [[GEP_DST]], align 8
187 ; CHECK-NEXT:    [[IV_NEXT:%.*]] = add nuw nsw i64 [[IV]], 1
188 ; CHECK-NEXT:    [[GEP_SRC_12_1:%.*]] = getelementptr i64, ptr [[SRC_12]], i64 [[IV_NEXT]]
189 ; CHECK-NEXT:    [[L_12_1:%.*]] = load i64, ptr [[GEP_SRC_12_1]], align 8
190 ; CHECK-NEXT:    [[GEP_SRC_4_1:%.*]] = getelementptr i64, ptr [[SRC_4]], i64 [[IV_NEXT]]
191 ; CHECK-NEXT:    [[L_4_1:%.*]] = load volatile i64, ptr [[GEP_SRC_4_1]], align 8
192 ; CHECK-NEXT:    [[MUL_1:%.*]] = mul i64 [[L_12_1]], [[L_4_1]]
193 ; CHECK-NEXT:    [[GEP_DST_1:%.*]] = getelementptr i64, ptr [[DST]], i64 [[IV_NEXT]]
194 ; CHECK-NEXT:    store i64 [[MUL_1]], ptr [[GEP_DST_1]], align 8
195 ; CHECK-NEXT:    [[IV_NEXT_1]] = add nuw nsw i64 [[IV]], 2
196 ; CHECK-NEXT:    [[NITER_NEXT_1]] = add i64 [[NITER]], 2
197 ; CHECK-NEXT:    [[NITER_NCMP_1:%.*]] = icmp eq i64 [[NITER_NEXT_1]], [[UNROLL_ITER]]
198 ; CHECK-NEXT:    br i1 [[NITER_NCMP_1]], label [[EXIT_UNR_LCSSA_LOOPEXIT:%.*]], label [[LOOP]], !llvm.loop [[LOOP4:![0-9]+]]
199 ; CHECK:       exit.unr-lcssa.loopexit:
200 ; CHECK-NEXT:    [[IV_UNR_PH:%.*]] = phi i64 [ [[IV_NEXT_1]], [[LOOP]] ]
201 ; CHECK-NEXT:    br label [[EXIT_UNR_LCSSA]]
202 ; CHECK:       exit.unr-lcssa:
203 ; CHECK-NEXT:    [[IV_UNR:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_UNR_PH]], [[EXIT_UNR_LCSSA_LOOPEXIT]] ]
204 ; CHECK-NEXT:    [[LCMP_MOD:%.*]] = icmp ne i64 [[XTRAITER]], 0
205 ; CHECK-NEXT:    br i1 [[LCMP_MOD]], label [[LOOP_EPIL_PREHEADER:%.*]], label [[EXIT:%.*]]
206 ; CHECK:       loop.epil.preheader:
207 ; CHECK-NEXT:    br label [[LOOP_EPIL:%.*]]
208 ; CHECK:       loop.epil:
209 ; CHECK-NEXT:    [[GEP_SRC_12_EPIL:%.*]] = getelementptr i64, ptr [[SRC_12]], i64 [[IV_UNR]]
210 ; CHECK-NEXT:    [[L_12_EPIL:%.*]] = load i64, ptr [[GEP_SRC_12_EPIL]], align 8
211 ; CHECK-NEXT:    [[GEP_SRC_4_EPIL:%.*]] = getelementptr i64, ptr [[SRC_4]], i64 [[IV_UNR]]
212 ; CHECK-NEXT:    [[L_4_EPIL:%.*]] = load volatile i64, ptr [[GEP_SRC_4_EPIL]], align 8
213 ; CHECK-NEXT:    [[MUL_EPIL:%.*]] = mul i64 [[L_12_EPIL]], [[L_4_EPIL]]
214 ; CHECK-NEXT:    [[GEP_DST_EPIL:%.*]] = getelementptr i64, ptr [[DST]], i64 [[IV_UNR]]
215 ; CHECK-NEXT:    store i64 [[MUL_EPIL]], ptr [[GEP_DST_EPIL]], align 8
216 ; CHECK-NEXT:    br label [[EXIT]]
217 ; CHECK:       exit:
218 ; CHECK-NEXT:    ret void
220 entry:
221   %src.4 = getelementptr i8, ptr %src, i64 4
222   %src.12 = getelementptr i8, ptr %src, i64 12
223   br label %loop
225 loop:
226   %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
227   %gep.src.12 = getelementptr i64, ptr %src.12, i64 %iv
228   %l.12 = load i64, ptr %gep.src.12, align 8
229   %gep.src.4 = getelementptr i64, ptr %src.4, i64 %iv
230   %l.4 = load volatile i64, ptr %gep.src.4, align 8
231   %mul = mul i64 %l.12, %l.4
232   %gep.dst = getelementptr i64, ptr %dst, i64 %iv
233   store i64 %mul, ptr %gep.dst
234   %iv.next = add nuw nsw i64 %iv, 1
235   %c = icmp eq i64 %iv.next, %N
236   br i1 %c, label %exit, label %loop, !llvm.loop !1
238 exit:
239   ret void
242 define void @cse_atomic_loads(ptr %src, ptr noalias %dst, i64 %N) {
243 ; CHECK-LABEL: define void @cse_atomic_loads(
244 ; CHECK-SAME: ptr [[SRC:%.*]], ptr noalias [[DST:%.*]], i64 [[N:%.*]]) {
245 ; CHECK-NEXT:  entry:
246 ; CHECK-NEXT:    [[SRC_4:%.*]] = getelementptr i8, ptr [[SRC]], i64 4
247 ; CHECK-NEXT:    [[SRC_12:%.*]] = getelementptr i8, ptr [[SRC]], i64 12
248 ; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[N]], -1
249 ; CHECK-NEXT:    [[XTRAITER:%.*]] = and i64 [[N]], 1
250 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 1
251 ; CHECK-NEXT:    br i1 [[TMP1]], label [[EXIT_UNR_LCSSA:%.*]], label [[ENTRY_NEW:%.*]]
252 ; CHECK:       entry.new:
253 ; CHECK-NEXT:    [[UNROLL_ITER:%.*]] = sub i64 [[N]], [[XTRAITER]]
254 ; CHECK-NEXT:    br label [[LOOP:%.*]]
255 ; CHECK:       loop:
256 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY_NEW]] ], [ [[IV_NEXT_1:%.*]], [[LOOP]] ]
257 ; CHECK-NEXT:    [[NITER:%.*]] = phi i64 [ 0, [[ENTRY_NEW]] ], [ [[NITER_NEXT_1:%.*]], [[LOOP]] ]
258 ; CHECK-NEXT:    [[GEP_SRC_12:%.*]] = getelementptr i64, ptr [[SRC_12]], i64 [[IV]]
259 ; CHECK-NEXT:    [[L_12:%.*]] = load i64, ptr [[GEP_SRC_12]], align 8
260 ; CHECK-NEXT:    [[GEP_SRC_4:%.*]] = getelementptr i64, ptr [[SRC_4]], i64 [[IV]]
261 ; CHECK-NEXT:    [[L_4:%.*]] = load atomic i64, ptr [[GEP_SRC_4]] unordered, align 8
262 ; CHECK-NEXT:    [[MUL:%.*]] = mul i64 [[L_12]], [[L_4]]
263 ; CHECK-NEXT:    [[GEP_DST:%.*]] = getelementptr i64, ptr [[DST]], i64 [[IV]]
264 ; CHECK-NEXT:    store i64 [[MUL]], ptr [[GEP_DST]], align 8
265 ; CHECK-NEXT:    [[IV_NEXT:%.*]] = add nuw nsw i64 [[IV]], 1
266 ; CHECK-NEXT:    [[GEP_SRC_12_1:%.*]] = getelementptr i64, ptr [[SRC_12]], i64 [[IV_NEXT]]
267 ; CHECK-NEXT:    [[L_12_1:%.*]] = load i64, ptr [[GEP_SRC_12_1]], align 8
268 ; CHECK-NEXT:    [[GEP_SRC_4_1:%.*]] = getelementptr i64, ptr [[SRC_4]], i64 [[IV_NEXT]]
269 ; CHECK-NEXT:    [[L_4_1:%.*]] = load atomic i64, ptr [[GEP_SRC_4_1]] unordered, align 8
270 ; CHECK-NEXT:    [[MUL_1:%.*]] = mul i64 [[L_12_1]], [[L_4_1]]
271 ; CHECK-NEXT:    [[GEP_DST_1:%.*]] = getelementptr i64, ptr [[DST]], i64 [[IV_NEXT]]
272 ; CHECK-NEXT:    store i64 [[MUL_1]], ptr [[GEP_DST_1]], align 8
273 ; CHECK-NEXT:    [[IV_NEXT_1]] = add nuw nsw i64 [[IV]], 2
274 ; CHECK-NEXT:    [[NITER_NEXT_1]] = add i64 [[NITER]], 2
275 ; CHECK-NEXT:    [[NITER_NCMP_1:%.*]] = icmp eq i64 [[NITER_NEXT_1]], [[UNROLL_ITER]]
276 ; CHECK-NEXT:    br i1 [[NITER_NCMP_1]], label [[EXIT_UNR_LCSSA_LOOPEXIT:%.*]], label [[LOOP]], !llvm.loop [[LOOP5:![0-9]+]]
277 ; CHECK:       exit.unr-lcssa.loopexit:
278 ; CHECK-NEXT:    [[IV_UNR_PH:%.*]] = phi i64 [ [[IV_NEXT_1]], [[LOOP]] ]
279 ; CHECK-NEXT:    br label [[EXIT_UNR_LCSSA]]
280 ; CHECK:       exit.unr-lcssa:
281 ; CHECK-NEXT:    [[IV_UNR:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_UNR_PH]], [[EXIT_UNR_LCSSA_LOOPEXIT]] ]
282 ; CHECK-NEXT:    [[LCMP_MOD:%.*]] = icmp ne i64 [[XTRAITER]], 0
283 ; CHECK-NEXT:    br i1 [[LCMP_MOD]], label [[LOOP_EPIL_PREHEADER:%.*]], label [[EXIT:%.*]]
284 ; CHECK:       loop.epil.preheader:
285 ; CHECK-NEXT:    br label [[LOOP_EPIL:%.*]]
286 ; CHECK:       loop.epil:
287 ; CHECK-NEXT:    [[GEP_SRC_12_EPIL:%.*]] = getelementptr i64, ptr [[SRC_12]], i64 [[IV_UNR]]
288 ; CHECK-NEXT:    [[L_12_EPIL:%.*]] = load i64, ptr [[GEP_SRC_12_EPIL]], align 8
289 ; CHECK-NEXT:    [[GEP_SRC_4_EPIL:%.*]] = getelementptr i64, ptr [[SRC_4]], i64 [[IV_UNR]]
290 ; CHECK-NEXT:    [[L_4_EPIL:%.*]] = load atomic i64, ptr [[GEP_SRC_4_EPIL]] unordered, align 8
291 ; CHECK-NEXT:    [[MUL_EPIL:%.*]] = mul i64 [[L_12_EPIL]], [[L_4_EPIL]]
292 ; CHECK-NEXT:    [[GEP_DST_EPIL:%.*]] = getelementptr i64, ptr [[DST]], i64 [[IV_UNR]]
293 ; CHECK-NEXT:    store i64 [[MUL_EPIL]], ptr [[GEP_DST_EPIL]], align 8
294 ; CHECK-NEXT:    br label [[EXIT]]
295 ; CHECK:       exit:
296 ; CHECK-NEXT:    ret void
298 entry:
299   %src.4 = getelementptr i8, ptr %src, i64 4
300   %src.12 = getelementptr i8, ptr %src, i64 12
301   br label %loop
303 loop:
304   %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
305   %gep.src.12 = getelementptr i64, ptr %src.12, i64 %iv
306   %l.12 = load i64, ptr %gep.src.12, align 8
307   %gep.src.4 = getelementptr i64, ptr %src.4, i64 %iv
308   %l.4 = load atomic i64, ptr %gep.src.4 unordered, align 8
309   %mul = mul i64 %l.12, %l.4
310   %gep.dst = getelementptr i64, ptr %dst, i64 %iv
311   store i64 %mul, ptr %gep.dst
312   %iv.next = add nuw nsw i64 %iv, 1
313   %c = icmp eq i64 %iv.next, %N
314   br i1 %c, label %exit, label %loop, !llvm.loop !1
316 exit:
317   ret void
320 define void @cse_load_may_be_clobbered(ptr %src, ptr %dst, i64 %N) {
321 ; CHECK-LABEL: define void @cse_load_may_be_clobbered(
322 ; CHECK-SAME: ptr [[SRC:%.*]], ptr [[DST:%.*]], i64 [[N:%.*]]) {
323 ; CHECK-NEXT:  entry:
324 ; CHECK-NEXT:    [[SRC_4:%.*]] = getelementptr i8, ptr [[SRC]], i64 4
325 ; CHECK-NEXT:    [[SRC_12:%.*]] = getelementptr i8, ptr [[SRC]], i64 12
326 ; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[N]], -1
327 ; CHECK-NEXT:    [[XTRAITER:%.*]] = and i64 [[N]], 1
328 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 1
329 ; CHECK-NEXT:    br i1 [[TMP1]], label [[EXIT_UNR_LCSSA:%.*]], label [[ENTRY_NEW:%.*]]
330 ; CHECK:       entry.new:
331 ; CHECK-NEXT:    [[UNROLL_ITER:%.*]] = sub i64 [[N]], [[XTRAITER]]
332 ; CHECK-NEXT:    br label [[LOOP:%.*]]
333 ; CHECK:       loop:
334 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY_NEW]] ], [ [[IV_NEXT_1:%.*]], [[LOOP]] ]
335 ; CHECK-NEXT:    [[NITER:%.*]] = phi i64 [ 0, [[ENTRY_NEW]] ], [ [[NITER_NEXT_1:%.*]], [[LOOP]] ]
336 ; CHECK-NEXT:    [[GEP_SRC_12:%.*]] = getelementptr i64, ptr [[SRC_12]], i64 [[IV]]
337 ; CHECK-NEXT:    [[L_12:%.*]] = load i64, ptr [[GEP_SRC_12]], align 8
338 ; CHECK-NEXT:    [[GEP_SRC_4:%.*]] = getelementptr i64, ptr [[SRC_4]], i64 [[IV]]
339 ; CHECK-NEXT:    [[L_4:%.*]] = load i64, ptr [[GEP_SRC_4]], align 8
340 ; CHECK-NEXT:    [[MUL:%.*]] = mul i64 [[L_12]], [[L_4]]
341 ; CHECK-NEXT:    [[GEP_DST:%.*]] = getelementptr i64, ptr [[DST]], i64 [[IV]]
342 ; CHECK-NEXT:    store i64 [[MUL]], ptr [[GEP_DST]], align 8
343 ; CHECK-NEXT:    [[IV_NEXT:%.*]] = add nuw nsw i64 [[IV]], 1
344 ; CHECK-NEXT:    [[GEP_SRC_12_1:%.*]] = getelementptr i64, ptr [[SRC_12]], i64 [[IV_NEXT]]
345 ; CHECK-NEXT:    [[L_12_1:%.*]] = load i64, ptr [[GEP_SRC_12_1]], align 8
346 ; CHECK-NEXT:    [[GEP_SRC_4_1:%.*]] = getelementptr i64, ptr [[SRC_4]], i64 [[IV_NEXT]]
347 ; CHECK-NEXT:    [[L_4_1:%.*]] = load i64, ptr [[GEP_SRC_4_1]], align 8
348 ; CHECK-NEXT:    [[MUL_1:%.*]] = mul i64 [[L_12_1]], [[L_4_1]]
349 ; CHECK-NEXT:    [[GEP_DST_1:%.*]] = getelementptr i64, ptr [[DST]], i64 [[IV_NEXT]]
350 ; CHECK-NEXT:    store i64 [[MUL_1]], ptr [[GEP_DST_1]], align 8
351 ; CHECK-NEXT:    [[IV_NEXT_1]] = add nuw nsw i64 [[IV]], 2
352 ; CHECK-NEXT:    [[NITER_NEXT_1]] = add i64 [[NITER]], 2
353 ; CHECK-NEXT:    [[NITER_NCMP_1:%.*]] = icmp eq i64 [[NITER_NEXT_1]], [[UNROLL_ITER]]
354 ; CHECK-NEXT:    br i1 [[NITER_NCMP_1]], label [[EXIT_UNR_LCSSA_LOOPEXIT:%.*]], label [[LOOP]], !llvm.loop [[LOOP6:![0-9]+]]
355 ; CHECK:       exit.unr-lcssa.loopexit:
356 ; CHECK-NEXT:    [[IV_UNR_PH:%.*]] = phi i64 [ [[IV_NEXT_1]], [[LOOP]] ]
357 ; CHECK-NEXT:    br label [[EXIT_UNR_LCSSA]]
358 ; CHECK:       exit.unr-lcssa:
359 ; CHECK-NEXT:    [[IV_UNR:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_UNR_PH]], [[EXIT_UNR_LCSSA_LOOPEXIT]] ]
360 ; CHECK-NEXT:    [[LCMP_MOD:%.*]] = icmp ne i64 [[XTRAITER]], 0
361 ; CHECK-NEXT:    br i1 [[LCMP_MOD]], label [[LOOP_EPIL_PREHEADER:%.*]], label [[EXIT:%.*]]
362 ; CHECK:       loop.epil.preheader:
363 ; CHECK-NEXT:    br label [[LOOP_EPIL:%.*]]
364 ; CHECK:       loop.epil:
365 ; CHECK-NEXT:    [[GEP_SRC_12_EPIL:%.*]] = getelementptr i64, ptr [[SRC_12]], i64 [[IV_UNR]]
366 ; CHECK-NEXT:    [[L_12_EPIL:%.*]] = load i64, ptr [[GEP_SRC_12_EPIL]], align 8
367 ; CHECK-NEXT:    [[GEP_SRC_4_EPIL:%.*]] = getelementptr i64, ptr [[SRC_4]], i64 [[IV_UNR]]
368 ; CHECK-NEXT:    [[L_4_EPIL:%.*]] = load i64, ptr [[GEP_SRC_4_EPIL]], align 8
369 ; CHECK-NEXT:    [[MUL_EPIL:%.*]] = mul i64 [[L_12_EPIL]], [[L_4_EPIL]]
370 ; CHECK-NEXT:    [[GEP_DST_EPIL:%.*]] = getelementptr i64, ptr [[DST]], i64 [[IV_UNR]]
371 ; CHECK-NEXT:    store i64 [[MUL_EPIL]], ptr [[GEP_DST_EPIL]], align 8
372 ; CHECK-NEXT:    br label [[EXIT]]
373 ; CHECK:       exit:
374 ; CHECK-NEXT:    ret void
376 entry:
377   %src.4 = getelementptr i8, ptr %src, i64 4
378   %src.12 = getelementptr i8, ptr %src, i64 12
379   br label %loop
381 loop:
382   %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
383   %gep.src.12 = getelementptr i64, ptr %src.12, i64 %iv
384   %l.12 = load i64, ptr %gep.src.12, align 8
385   %gep.src.4 = getelementptr i64, ptr %src.4, i64 %iv
386   %l.4 = load i64, ptr %gep.src.4, align 8
387   %mul = mul i64 %l.12, %l.4
388   %gep.dst = getelementptr i64, ptr %dst, i64 %iv
389   store i64 %mul, ptr %gep.dst
390   %iv.next = add nuw nsw i64 %iv, 1
391   %c = icmp eq i64 %iv.next, %N
392   br i1 %c, label %exit, label %loop, !llvm.loop !1
394 exit:
395   ret void
399 declare void @foo()
401 define void @loop_body_with_dead_blocks(ptr %src) {
402 ; CHECK-LABEL: define void @loop_body_with_dead_blocks(
403 ; CHECK-SAME: ptr [[SRC:%.*]]) {
404 ; CHECK-NEXT:  entry:
405 ; CHECK-NEXT:    br label [[OUTER_HEADER:%.*]]
406 ; CHECK:       outer.header.loopexit:
407 ; CHECK-NEXT:    br label [[OUTER_HEADER]]
408 ; CHECK:       outer.header:
409 ; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
410 ; CHECK:       loop.header:
411 ; CHECK-NEXT:    br label [[LOOP_BB:%.*]]
412 ; CHECK:       loop.bb.dead:
413 ; CHECK-NEXT:    unreachable
414 ; CHECK:       loop.bb:
415 ; CHECK-NEXT:    [[L_1:%.*]] = load i32, ptr [[SRC]], align 8
416 ; CHECK-NEXT:    [[C_1:%.*]] = icmp eq i32 [[L_1]], 0
417 ; CHECK-NEXT:    br i1 [[C_1]], label [[OUTER_HEADER_LOOPEXIT:%.*]], label [[LOOP_LATCH:%.*]]
418 ; CHECK:       loop.latch:
419 ; CHECK-NEXT:    call void @foo()
420 ; CHECK-NEXT:    [[L_2:%.*]] = load i32, ptr [[SRC]], align 8
421 ; CHECK-NEXT:    [[C_2:%.*]] = icmp eq i32 [[L_2]], 1
422 ; CHECK-NEXT:    br i1 [[C_2]], label [[EXIT:%.*]], label [[LOOP_HEADER_1:%.*]], !llvm.loop [[LOOP7:![0-9]+]]
423 ; CHECK:       loop.header.1:
424 ; CHECK-NEXT:    br label [[LOOP_BB_1:%.*]]
425 ; CHECK:       loop.bb.1:
426 ; CHECK-NEXT:    [[C_1_1:%.*]] = icmp eq i32 [[L_2]], 0
427 ; CHECK-NEXT:    br i1 [[C_1_1]], label [[OUTER_HEADER_LOOPEXIT]], label [[LOOP_LATCH_1:%.*]]
428 ; CHECK:       loop.latch.1:
429 ; CHECK-NEXT:    call void @foo()
430 ; CHECK-NEXT:    [[L_2_1:%.*]] = load i32, ptr [[SRC]], align 8
431 ; CHECK-NEXT:    [[C_2_1:%.*]] = icmp eq i32 [[L_2_1]], 1
432 ; CHECK-NEXT:    br i1 [[C_2_1]], label [[EXIT]], label [[LOOP_HEADER]], !llvm.loop [[LOOP9:![0-9]+]]
433 ; CHECK:       exit:
434 ; CHECK-NEXT:    ret void
436 entry:
437   br label %outer.header
439 outer.header:
440   br label %loop.header
442 loop.header:
443   br label %loop.bb
445 loop.bb.dead:
446   br label %loop.bb
448 loop.bb:
449   %l.1 = load i32, ptr %src, align 8
450   %c.1 = icmp eq i32 %l.1, 0
451   br i1 %c.1, label %outer.header, label %loop.latch
453 loop.latch:
454   call void @foo()
455   %l.2 = load i32, ptr %src, align 8
456   %c.2 = icmp eq i32 %l.2, 1
457   br i1 %c.2, label %exit, label %loop.header, !llvm.loop !1
459 exit:
460   ret void
463 !0 = !{!"llvm.loop.mustprogress"}
464 !1 = distinct !{!1, !0, !2}
465 !2 = !{!"llvm.loop.unroll.count", i32 2}
467 ; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]], [[META2:![0-9]+]]}
468 ; CHECK: [[META1]] = !{!"llvm.loop.mustprogress"}
469 ; CHECK: [[META2]] = !{!"llvm.loop.unroll.disable"}
470 ; CHECK: [[LOOP3]] = distinct !{[[LOOP3]], [[META1]], [[META2]]}
471 ; CHECK: [[LOOP4]] = distinct !{[[LOOP4]], [[META1]], [[META2]]}
472 ; CHECK: [[LOOP5]] = distinct !{[[LOOP5]], [[META1]], [[META2]]}
473 ; CHECK: [[LOOP6]] = distinct !{[[LOOP6]], [[META1]], [[META2]]}
474 ; CHECK: [[LOOP7]] = distinct !{[[LOOP7]], [[META1]], [[META8:![0-9]+]]}
475 ; CHECK: [[META8]] = !{!"llvm.loop.unroll.count", i32 2}
476 ; CHECK: [[LOOP9]] = distinct !{[[LOOP9]], [[META1]], [[META2]]}