xref: /llvm-project/llvm/test/CodeGen/X86/usub_inc_iv.ll (revision 2f448bf509432c1a19ec46ab8cbc7353c03c6280)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -mtriple=x86_64-linux -codegenprepare -S < %s | FileCheck %s
3
4define i32 @test_01(ptr %p, i64 %len, i32 %x) {
5; CHECK-LABEL: @test_01(
6; CHECK-NEXT:  entry:
7; CHECK-NEXT:    br label [[LOOP:%.*]]
8; CHECK:       loop:
9; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[MATH:%.*]], [[BACKEDGE:%.*]] ], [ [[LEN:%.*]], [[ENTRY:%.*]] ]
10; CHECK-NEXT:    [[TMP0:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[IV]], i64 1)
11; CHECK-NEXT:    [[MATH]] = extractvalue { i64, i1 } [[TMP0]], 0
12; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i64, i1 } [[TMP0]], 1
13; CHECK-NEXT:    br i1 [[OV]], label [[EXIT:%.*]], label [[BACKEDGE]]
14; CHECK:       backedge:
15; CHECK-NEXT:    [[SUNKADDR:%.*]] = mul i64 [[MATH]], 4
16; CHECK-NEXT:    [[SUNKADDR1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[SUNKADDR]]
17; CHECK-NEXT:    [[LOADED:%.*]] = load atomic i32, ptr [[SUNKADDR1]] unordered, align 4
18; CHECK-NEXT:    [[COND_2:%.*]] = icmp eq i32 [[LOADED]], [[X:%.*]]
19; CHECK-NEXT:    br i1 [[COND_2]], label [[FAILURE:%.*]], label [[LOOP]]
20; CHECK:       exit:
21; CHECK-NEXT:    ret i32 -1
22; CHECK:       failure:
23; CHECK-NEXT:    unreachable
24;
25entry:
26  %scevgep = getelementptr i32, ptr %p, i64 -1
27  br label %loop
28
29loop:                                             ; preds = %backedge, %entry
30  %iv = phi i64 [ %iv.next, %backedge ], [ %len, %entry ]
31  %iv.next = add i64 %iv, -1
32  %cond_1 = icmp eq i64 %iv, 0
33  br i1 %cond_1, label %exit, label %backedge
34
35backedge:                                         ; preds = %loop
36  %scevgep1 = getelementptr i32, ptr %scevgep, i64 %iv
37  %loaded = load atomic i32, ptr %scevgep1 unordered, align 4
38  %cond_2 = icmp eq i32 %loaded, %x
39  br i1 %cond_2, label %failure, label %loop
40
41exit:                                             ; preds = %loop
42  ret i32 -1
43
44failure:                                          ; preds = %backedge
45  unreachable
46}
47
48; Similar to test_01, but with different offset.
49define i32 @test_01a(ptr %p, i64 %len, i32 %x) {
50; CHECK-LABEL: @test_01a(
51; CHECK-NEXT:  entry:
52; CHECK-NEXT:    br label [[LOOP:%.*]]
53; CHECK:       loop:
54; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[MATH:%.*]], [[BACKEDGE:%.*]] ], [ [[LEN:%.*]], [[ENTRY:%.*]] ]
55; CHECK-NEXT:    [[TMP0:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[IV]], i64 1)
56; CHECK-NEXT:    [[MATH]] = extractvalue { i64, i1 } [[TMP0]], 0
57; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i64, i1 } [[TMP0]], 1
58; CHECK-NEXT:    br i1 [[OV]], label [[EXIT:%.*]], label [[BACKEDGE]]
59; CHECK:       backedge:
60; CHECK-NEXT:    [[SUNKADDR:%.*]] = mul i64 [[MATH]], 4
61; CHECK-NEXT:    [[SUNKADDR1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[SUNKADDR]]
62; CHECK-NEXT:    [[SUNKADDR2:%.*]] = getelementptr i8, ptr [[SUNKADDR1]], i64 -24
63; CHECK-NEXT:    [[LOADED:%.*]] = load atomic i32, ptr [[SUNKADDR2]] unordered, align 4
64; CHECK-NEXT:    [[COND_2:%.*]] = icmp eq i32 [[LOADED]], [[X:%.*]]
65; CHECK-NEXT:    br i1 [[COND_2]], label [[FAILURE:%.*]], label [[LOOP]]
66; CHECK:       exit:
67; CHECK-NEXT:    ret i32 -1
68; CHECK:       failure:
69; CHECK-NEXT:    unreachable
70;
71entry:
72  %scevgep = getelementptr i32, ptr %p, i64 -7
73  br label %loop
74
75loop:                                             ; preds = %backedge, %entry
76  %iv = phi i64 [ %iv.next, %backedge ], [ %len, %entry ]
77  %iv.next = add i64 %iv, -1
78  %cond_1 = icmp eq i64 %iv, 0
79  br i1 %cond_1, label %exit, label %backedge
80
81backedge:                                         ; preds = %loop
82  %scevgep1 = getelementptr i32, ptr %scevgep, i64 %iv
83  %loaded = load atomic i32, ptr %scevgep1 unordered, align 4
84  %cond_2 = icmp eq i32 %loaded, %x
85  br i1 %cond_2, label %failure, label %loop
86
87exit:                                             ; preds = %loop
88  ret i32 -1
89
90failure:                                          ; preds = %backedge
91  unreachable
92}
93
94; TODO: We can use trick with usub here.
95define i32 @test_02(ptr %p, i64 %len, i32 %x) {
96; CHECK-LABEL: @test_02(
97; CHECK-NEXT:  entry:
98; CHECK-NEXT:    br label [[LOOP:%.*]]
99; CHECK:       loop:
100; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[MATH:%.*]], [[BACKEDGE:%.*]] ], [ [[LEN:%.*]], [[ENTRY:%.*]] ]
101; CHECK-NEXT:    [[TMP0:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[IV]], i64 1)
102; CHECK-NEXT:    [[MATH]] = extractvalue { i64, i1 } [[TMP0]], 0
103; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i64, i1 } [[TMP0]], 1
104; CHECK-NEXT:    br i1 [[OV]], label [[EXIT:%.*]], label [[BACKEDGE]]
105; CHECK:       backedge:
106; CHECK-NEXT:    [[SUNKADDR:%.*]] = mul i64 [[MATH]], 4
107; CHECK-NEXT:    [[SUNKADDR1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[SUNKADDR]]
108; CHECK-NEXT:    [[LOADED:%.*]] = load atomic i32, ptr [[SUNKADDR1]] unordered, align 4
109; CHECK-NEXT:    [[COND_2:%.*]] = icmp eq i32 [[LOADED]], [[X:%.*]]
110; CHECK-NEXT:    br i1 [[COND_2]], label [[FAILURE:%.*]], label [[LOOP]]
111; CHECK:       exit:
112; CHECK-NEXT:    ret i32 -1
113; CHECK:       failure:
114; CHECK-NEXT:    unreachable
115;
116entry:
117  %scevgep = getelementptr i32, ptr %p, i64 -1
118  br label %loop
119
120loop:                                             ; preds = %backedge, %entry
121  %iv = phi i64 [ %iv.next, %backedge ], [ %len, %entry ]
122  %cond_1 = icmp eq i64 %iv, 0
123  br i1 %cond_1, label %exit, label %backedge
124
125backedge:                                         ; preds = %loop
126  %scevgep1 = getelementptr i32, ptr %scevgep, i64 %iv
127  %loaded = load atomic i32, ptr %scevgep1 unordered, align 4
128  %cond_2 = icmp eq i32 %loaded, %x
129  %iv.next = add i64 %iv, -1
130  br i1 %cond_2, label %failure, label %loop
131
132exit:                                             ; preds = %loop
133  ret i32 -1
134
135failure:                                          ; preds = %backedge
136  unreachable
137}
138
139declare i1 @use(i64 %x)
140declare i1 @some_cond()
141
142; Make sure we do not move the increment below the point where it is used.
143define i32 @test_03_neg(ptr %p, i64 %len, i32 %x) {
144; CHECK-LABEL: @test_03_neg(
145; CHECK-NEXT:  entry:
146; CHECK-NEXT:    br label [[LOOP:%.*]]
147; CHECK:       loop:
148; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ [[LEN:%.*]], [[ENTRY:%.*]] ]
149; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], -1
150; CHECK-NEXT:    [[COND_0:%.*]] = call i1 @use(i64 [[IV_NEXT]])
151; CHECK-NEXT:    br i1 [[COND_0]], label [[MIDDLE:%.*]], label [[FAILURE:%.*]]
152; CHECK:       middle:
153; CHECK-NEXT:    [[COND_1:%.*]] = icmp eq i64 [[IV]], 0
154; CHECK-NEXT:    br i1 [[COND_1]], label [[EXIT:%.*]], label [[BACKEDGE]]
155; CHECK:       backedge:
156; CHECK-NEXT:    [[SUNKADDR:%.*]] = mul i64 [[IV_NEXT]], 4
157; CHECK-NEXT:    [[SUNKADDR1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[SUNKADDR]]
158; CHECK-NEXT:    [[LOADED:%.*]] = load atomic i32, ptr [[SUNKADDR1]] unordered, align 4
159; CHECK-NEXT:    [[COND_2:%.*]] = icmp eq i32 [[LOADED]], [[X:%.*]]
160; CHECK-NEXT:    br i1 [[COND_2]], label [[FAILURE]], label [[LOOP]]
161; CHECK:       exit:
162; CHECK-NEXT:    ret i32 -1
163; CHECK:       failure:
164; CHECK-NEXT:    unreachable
165;
166entry:
167  %scevgep = getelementptr i32, ptr %p, i64 -1
168  br label %loop
169
170loop:                                             ; preds = %backedge, %entry
171  %iv = phi i64 [ %iv.next, %backedge ], [ %len, %entry ]
172  %iv.next = add i64 %iv, -1
173  %cond_0 = call i1 @use(i64 %iv.next)
174  br i1 %cond_0, label %middle, label %failure
175
176middle:
177  %cond_1 = icmp eq i64 %iv, 0
178  br i1 %cond_1, label %exit, label %backedge
179
180backedge:                                         ; preds = %loop
181  %scevgep1 = getelementptr i32, ptr %scevgep, i64 %iv
182  %loaded = load atomic i32, ptr %scevgep1 unordered, align 4
183  %cond_2 = icmp eq i32 %loaded, %x
184  br i1 %cond_2, label %failure, label %loop
185
186exit:                                             ; preds = %loop
187  ret i32 -1
188
189failure:                                          ; preds = %backedge
190  unreachable
191}
192
193define i32 @test_04_neg(ptr %p, i64 %len, i32 %x) {
194; CHECK-LABEL: @test_04_neg(
195; CHECK-NEXT:  entry:
196; CHECK-NEXT:    br label [[LOOP:%.*]]
197; CHECK:       loop:
198; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ [[LEN:%.*]], [[ENTRY:%.*]] ]
199; CHECK-NEXT:    br label [[INNER:%.*]]
200; CHECK:       inner:
201; CHECK-NEXT:    [[COND_1:%.*]] = icmp eq i64 [[IV]], 0
202; CHECK-NEXT:    br i1 [[COND_1]], label [[INNER_BACKEDGE:%.*]], label [[EXIT:%.*]]
203; CHECK:       inner_backedge:
204; CHECK-NEXT:    [[COND_INNER:%.*]] = call i1 @some_cond()
205; CHECK-NEXT:    br i1 [[COND_INNER]], label [[INNER]], label [[BACKEDGE]]
206; CHECK:       backedge:
207; CHECK-NEXT:    [[SUNKADDR:%.*]] = mul i64 [[IV]], 4
208; CHECK-NEXT:    [[SUNKADDR1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[SUNKADDR]]
209; CHECK-NEXT:    [[SUNKADDR2:%.*]] = getelementptr i8, ptr [[SUNKADDR1]], i64 -4
210; CHECK-NEXT:    [[LOADED:%.*]] = load atomic i32, ptr [[SUNKADDR2]] unordered, align 4
211; CHECK-NEXT:    [[COND_2:%.*]] = icmp eq i32 [[LOADED]], [[X:%.*]]
212; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], -1
213; CHECK-NEXT:    br i1 [[COND_2]], label [[FAILURE:%.*]], label [[LOOP]]
214; CHECK:       exit:
215; CHECK-NEXT:    ret i32 -1
216; CHECK:       failure:
217; CHECK-NEXT:    unreachable
218;
219entry:
220  %scevgep = getelementptr i32, ptr %p, i64 -1
221  br label %loop
222
223loop:
224  %iv = phi i64 [ %iv.next, %backedge ], [ %len, %entry ]
225  br label %inner
226
227inner:
228  %cond_1 = icmp eq i64 %iv, 0
229  br i1 %cond_1, label %inner_backedge, label %exit
230
231inner_backedge:
232  %cond_inner = call i1 @some_cond()
233  br i1 %cond_inner, label %inner, label %backedge
234
235backedge:
236  %scevgep1 = getelementptr i32, ptr %scevgep, i64 %iv
237  %loaded = load atomic i32, ptr %scevgep1 unordered, align 4
238  %cond_2 = icmp eq i32 %loaded, %x
239  %iv.next = add i64 %iv, -1
240  br i1 %cond_2, label %failure, label %loop
241
242exit:
243  ret i32 -1
244
245failure:
246  unreachable
247}
248
249; Here Cmp does not dominate latch.
250define i32 @test_05_neg(ptr %p, i64 %len, i32 %x, i1 %cond) {
251; CHECK-LABEL: @test_05_neg(
252; CHECK-NEXT:  entry:
253; CHECK-NEXT:    br label [[LOOP:%.*]]
254; CHECK:       loop:
255; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ [[LEN:%.*]], [[ENTRY:%.*]] ]
256; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], -1
257; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[BACKEDGE]]
258; CHECK:       if.true:
259; CHECK-NEXT:    [[COND_1:%.*]] = icmp eq i64 [[IV]], 0
260; CHECK-NEXT:    br i1 [[COND_1]], label [[EXIT:%.*]], label [[BACKEDGE]]
261; CHECK:       backedge:
262; CHECK-NEXT:    [[SUNKADDR:%.*]] = mul i64 [[IV_NEXT]], 4
263; CHECK-NEXT:    [[SUNKADDR1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[SUNKADDR]]
264; CHECK-NEXT:    [[LOADED:%.*]] = load atomic i32, ptr [[SUNKADDR1]] unordered, align 4
265; CHECK-NEXT:    [[COND_2:%.*]] = icmp eq i32 [[LOADED]], [[X:%.*]]
266; CHECK-NEXT:    br i1 [[COND_2]], label [[FAILURE:%.*]], label [[LOOP]]
267; CHECK:       exit:
268; CHECK-NEXT:    ret i32 -1
269; CHECK:       failure:
270; CHECK-NEXT:    unreachable
271;
272entry:
273  %scevgep = getelementptr i32, ptr %p, i64 -1
274  br label %loop
275
276loop:                                             ; preds = %backedge, %entry
277  %iv = phi i64 [ %iv.next, %backedge ], [ %len, %entry ]
278  %iv.next = add i64 %iv, -1
279  br i1 %cond, label %if.true, label %backedge
280
281if.true:
282  %cond_1 = icmp eq i64 %iv, 0
283  br i1 %cond_1, label %exit, label %backedge
284
285backedge:                                         ; preds = %loop
286  %scevgep1 = getelementptr i32, ptr %scevgep, i64 %iv
287  %loaded = load atomic i32, ptr %scevgep1 unordered, align 4
288  %cond_2 = icmp eq i32 %loaded, %x
289  br i1 %cond_2, label %failure, label %loop
290
291exit:                                             ; preds = %loop
292  ret i32 -1
293
294failure:                                          ; preds = %backedge
295  unreachable
296}
297
298
299; test_01, but with an additional use of %iv.next outside the loop
300define i32 @test_06(ptr %p, i64 %len, i32 %x) {
301; CHECK-LABEL: @test_06(
302; CHECK-NEXT:  entry:
303; CHECK-NEXT:    br label [[LOOP:%.*]]
304; CHECK:       loop:
305; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[MATH:%.*]], [[BACKEDGE:%.*]] ], [ [[LEN:%.*]], [[ENTRY:%.*]] ]
306; CHECK-NEXT:    [[TMP0:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[IV]], i64 1)
307; CHECK-NEXT:    [[MATH]] = extractvalue { i64, i1 } [[TMP0]], 0
308; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i64, i1 } [[TMP0]], 1
309; CHECK-NEXT:    br i1 [[OV]], label [[EXIT:%.*]], label [[BACKEDGE]]
310; CHECK:       backedge:
311; CHECK-NEXT:    [[SUNKADDR:%.*]] = mul i64 [[MATH]], 4
312; CHECK-NEXT:    [[SUNKADDR1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[SUNKADDR]]
313; CHECK-NEXT:    [[LOADED:%.*]] = load atomic i32, ptr [[SUNKADDR1]] unordered, align 4
314; CHECK-NEXT:    [[COND_2:%.*]] = icmp eq i32 [[LOADED]], [[X:%.*]]
315; CHECK-NEXT:    br i1 [[COND_2]], label [[FAILURE:%.*]], label [[LOOP]]
316; CHECK:       exit:
317; CHECK-NEXT:    ret i32 -1
318; CHECK:       failure:
319; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i64 [[MATH]] to i32
320; CHECK-NEXT:    ret i32 [[TRUNC]]
321;
322entry:
323  %scevgep = getelementptr i32, ptr %p, i64 -1
324  br label %loop
325
326loop:                                             ; preds = %backedge, %entry
327  %iv = phi i64 [ %iv.next, %backedge ], [ %len, %entry ]
328  %cond_1 = icmp eq i64 %iv, 0
329  br i1 %cond_1, label %exit, label %backedge
330
331backedge:                                         ; preds = %loop
332  %scevgep1 = getelementptr i32, ptr %scevgep, i64 %iv
333  %loaded = load atomic i32, ptr %scevgep1 unordered, align 4
334  %iv.next = add i64 %iv, -1
335  %cond_2 = icmp eq i32 %loaded, %x
336  br i1 %cond_2, label %failure, label %loop
337
338exit:
339  ret i32 -1
340
341failure:
342  %trunc = trunc i64 %iv.next to i32
343  ret i32 %trunc
344}
345
346
347; Extra use outside loop which prevents us moving the increment to the cmp
348define i32 @test_07_neg(ptr %p, i64 %len, i32 %x) {
349; CHECK-LABEL: @test_07_neg(
350; CHECK-NEXT:  entry:
351; CHECK-NEXT:    br label [[LOOP:%.*]]
352; CHECK:       loop:
353; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ [[LEN:%.*]], [[ENTRY:%.*]] ]
354; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], -1
355; CHECK-NEXT:    [[SUNKADDR:%.*]] = mul i64 [[IV_NEXT]], 4
356; CHECK-NEXT:    [[SUNKADDR1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[SUNKADDR]]
357; CHECK-NEXT:    [[LOADED:%.*]] = load atomic i32, ptr [[SUNKADDR1]] unordered, align 4
358; CHECK-NEXT:    [[COND_2:%.*]] = icmp eq i32 [[LOADED]], [[X:%.*]]
359; CHECK-NEXT:    br i1 [[COND_2]], label [[FAILURE:%.*]], label [[BACKEDGE]]
360; CHECK:       backedge:
361; CHECK-NEXT:    [[COND_1:%.*]] = icmp eq i64 [[IV]], 0
362; CHECK-NEXT:    br i1 [[COND_1]], label [[EXIT:%.*]], label [[LOOP]]
363; CHECK:       exit:
364; CHECK-NEXT:    ret i32 -1
365; CHECK:       failure:
366; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i64 [[IV_NEXT]] to i32
367; CHECK-NEXT:    ret i32 [[TRUNC]]
368;
369entry:
370  %scevgep = getelementptr i32, ptr %p, i64 -1
371  br label %loop
372
373loop:
374  %iv = phi i64 [ %iv.next, %backedge ], [ %len, %entry ]
375  %iv.next = add i64 %iv, -1
376  %scevgep1 = getelementptr i32, ptr %scevgep, i64 %iv
377  %loaded = load atomic i32, ptr %scevgep1 unordered, align 4
378  %cond_2 = icmp eq i32 %loaded, %x
379  br i1 %cond_2, label %failure, label %backedge
380
381backedge:
382  %cond_1 = icmp eq i64 %iv, 0
383  br i1 %cond_1, label %exit, label %loop
384
385exit:
386  ret i32 -1
387
388failure:
389  %trunc = trunc i64 %iv.next to i32
390  ret i32 %trunc
391}
392