xref: /llvm-project/llvm/test/Transforms/AggressiveInstCombine/rotate.ll (revision 7c802f985f2c28985c233d05b559a4e8c92110ae)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=aggressive-instcombine -S | FileCheck %s
3
4; https://bugs.llvm.org/show_bug.cgi?id=34924
5
6define i32 @rotl(i32 %a, i32 %b) {
7; CHECK-LABEL: @rotl(
8; CHECK-NEXT:  entry:
9; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0
10; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]]
11; CHECK:       rotbb:
12; CHECK-NEXT:    br label [[END]]
13; CHECK:       end:
14; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.fshl.i32(i32 [[A:%.*]], i32 [[A]], i32 [[B]])
15; CHECK-NEXT:    ret i32 [[TMP0]]
16;
17entry:
18  %cmp = icmp eq i32 %b, 0
19  br i1 %cmp, label %end, label %rotbb
20
21rotbb:
22  %sub = sub i32 32, %b
23  %shr = lshr i32 %a, %sub
24  %shl = shl i32 %a, %b
25  %or = or i32 %shr, %shl
26  br label %end
27
28end:
29  %cond = phi i32 [ %or, %rotbb ], [ %a, %entry ]
30  ret i32 %cond
31}
32
33define i32 @rotl_commute_phi(i32 %a, i32 %b) {
34; CHECK-LABEL: @rotl_commute_phi(
35; CHECK-NEXT:  entry:
36; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0
37; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]]
38; CHECK:       rotbb:
39; CHECK-NEXT:    br label [[END]]
40; CHECK:       end:
41; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.fshl.i32(i32 [[A:%.*]], i32 [[A]], i32 [[B]])
42; CHECK-NEXT:    ret i32 [[TMP0]]
43;
44entry:
45  %cmp = icmp eq i32 %b, 0
46  br i1 %cmp, label %end, label %rotbb
47
48rotbb:
49  %sub = sub i32 32, %b
50  %shr = lshr i32 %a, %sub
51  %shl = shl i32 %a, %b
52  %or = or i32 %shr, %shl
53  br label %end
54
55end:
56  %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ]
57  ret i32 %cond
58}
59
60define i32 @rotl_commute_or(i32 %a, i32 %b) {
61; CHECK-LABEL: @rotl_commute_or(
62; CHECK-NEXT:  entry:
63; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0
64; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]]
65; CHECK:       rotbb:
66; CHECK-NEXT:    br label [[END]]
67; CHECK:       end:
68; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.fshl.i32(i32 [[A:%.*]], i32 [[A]], i32 [[B]])
69; CHECK-NEXT:    ret i32 [[TMP0]]
70;
71entry:
72  %cmp = icmp eq i32 %b, 0
73  br i1 %cmp, label %end, label %rotbb
74
75rotbb:
76  %sub = sub i32 32, %b
77  %shr = lshr i32 %a, %sub
78  %shl = shl i32 %a, %b
79  %or = or i32 %shl, %shr
80  br label %end
81
82end:
83  %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ]
84  ret i32 %cond
85}
86
87; Verify that the intrinsic is inserted into a valid position.
88
89define i32 @rotl_insert_valid_location(i32 %a, i32 %b) {
90; CHECK-LABEL: @rotl_insert_valid_location(
91; CHECK-NEXT:  entry:
92; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0
93; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]]
94; CHECK:       rotbb:
95; CHECK-NEXT:    br label [[END]]
96; CHECK:       end:
97; CHECK-NEXT:    [[OTHER:%.*]] = phi i32 [ 1, [[ROTBB]] ], [ 2, [[ENTRY:%.*]] ]
98; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.fshl.i32(i32 [[A:%.*]], i32 [[A]], i32 [[B]])
99; CHECK-NEXT:    [[RES:%.*]] = or i32 [[TMP0]], [[OTHER]]
100; CHECK-NEXT:    ret i32 [[RES]]
101;
102entry:
103  %cmp = icmp eq i32 %b, 0
104  br i1 %cmp, label %end, label %rotbb
105
106rotbb:
107  %sub = sub i32 32, %b
108  %shr = lshr i32 %a, %sub
109  %shl = shl i32 %a, %b
110  %or = or i32 %shr, %shl
111  br label %end
112
113end:
114  %cond = phi i32 [ %or, %rotbb ], [ %a, %entry ]
115  %other = phi i32 [ 1, %rotbb ], [ 2, %entry ]
116  %res = or i32 %cond, %other
117  ret i32 %res
118}
119
120define i32 @rotr(i32 %a, i32 %b) {
121; CHECK-LABEL: @rotr(
122; CHECK-NEXT:  entry:
123; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0
124; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]]
125; CHECK:       rotbb:
126; CHECK-NEXT:    br label [[END]]
127; CHECK:       end:
128; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.fshr.i32(i32 [[A:%.*]], i32 [[A]], i32 [[B]])
129; CHECK-NEXT:    ret i32 [[TMP0]]
130;
131entry:
132  %cmp = icmp eq i32 %b, 0
133  br i1 %cmp, label %end, label %rotbb
134
135rotbb:
136  %sub = sub i32 32, %b
137  %shl = shl i32 %a, %sub
138  %shr = lshr i32 %a, %b
139  %or = or i32 %shr, %shl
140  br label %end
141
142end:
143  %cond = phi i32 [ %or, %rotbb ], [ %a, %entry ]
144  ret i32 %cond
145}
146
147define i32 @rotr_commute_phi(i32 %a, i32 %b) {
148; CHECK-LABEL: @rotr_commute_phi(
149; CHECK-NEXT:  entry:
150; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0
151; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]]
152; CHECK:       rotbb:
153; CHECK-NEXT:    br label [[END]]
154; CHECK:       end:
155; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.fshr.i32(i32 [[A:%.*]], i32 [[A]], i32 [[B]])
156; CHECK-NEXT:    ret i32 [[TMP0]]
157;
158entry:
159  %cmp = icmp eq i32 %b, 0
160  br i1 %cmp, label %end, label %rotbb
161
162rotbb:
163  %sub = sub i32 32, %b
164  %shl = shl i32 %a, %sub
165  %shr = lshr i32 %a, %b
166  %or = or i32 %shr, %shl
167  br label %end
168
169end:
170  %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ]
171  ret i32 %cond
172}
173
174define i32 @rotr_commute_or(i32 %a, i32 %b) {
175; CHECK-LABEL: @rotr_commute_or(
176; CHECK-NEXT:  entry:
177; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0
178; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]]
179; CHECK:       rotbb:
180; CHECK-NEXT:    br label [[END]]
181; CHECK:       end:
182; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.fshr.i32(i32 [[A:%.*]], i32 [[A]], i32 [[B]])
183; CHECK-NEXT:    ret i32 [[TMP0]]
184;
185entry:
186  %cmp = icmp eq i32 %b, 0
187  br i1 %cmp, label %end, label %rotbb
188
189rotbb:
190  %sub = sub i32 32, %b
191  %shl = shl i32 %a, %sub
192  %shr = lshr i32 %a, %b
193  %or = or i32 %shl, %shr
194  br label %end
195
196end:
197  %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ]
198  ret i32 %cond
199}
200
201; Negative test - non-power-of-2 might require urem expansion in the backend.
202
203define i12 @could_be_rotr_weird_type(i12 %a, i12 %b) {
204; CHECK-LABEL: @could_be_rotr_weird_type(
205; CHECK-NEXT:  entry:
206; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i12 [[B:%.*]], 0
207; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]]
208; CHECK:       rotbb:
209; CHECK-NEXT:    [[SUB:%.*]] = sub i12 12, [[B]]
210; CHECK-NEXT:    [[SHL:%.*]] = shl i12 [[A:%.*]], [[SUB]]
211; CHECK-NEXT:    [[SHR:%.*]] = lshr i12 [[A]], [[B]]
212; CHECK-NEXT:    [[OR:%.*]] = or i12 [[SHL]], [[SHR]]
213; CHECK-NEXT:    br label [[END]]
214; CHECK:       end:
215; CHECK-NEXT:    [[COND:%.*]] = phi i12 [ [[A]], [[ENTRY:%.*]] ], [ [[OR]], [[ROTBB]] ]
216; CHECK-NEXT:    ret i12 [[COND]]
217;
218entry:
219  %cmp = icmp eq i12 %b, 0
220  br i1 %cmp, label %end, label %rotbb
221
222rotbb:
223  %sub = sub i12 12, %b
224  %shl = shl i12 %a, %sub
225  %shr = lshr i12 %a, %b
226  %or = or i12 %shl, %shr
227  br label %end
228
229end:
230  %cond = phi i12 [ %a, %entry ], [ %or, %rotbb ]
231  ret i12 %cond
232}
233
234; Negative test - wrong phi ops.
235
236define i32 @not_rotr_1(i32 %a, i32 %b) {
237; CHECK-LABEL: @not_rotr_1(
238; CHECK-NEXT:  entry:
239; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0
240; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]]
241; CHECK:       rotbb:
242; CHECK-NEXT:    [[SUB:%.*]] = sub i32 32, [[B]]
243; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]
244; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[A]], [[B]]
245; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHL]], [[SHR]]
246; CHECK-NEXT:    br label [[END]]
247; CHECK:       end:
248; CHECK-NEXT:    [[COND:%.*]] = phi i32 [ [[B]], [[ENTRY:%.*]] ], [ [[OR]], [[ROTBB]] ]
249; CHECK-NEXT:    ret i32 [[COND]]
250;
251entry:
252  %cmp = icmp eq i32 %b, 0
253  br i1 %cmp, label %end, label %rotbb
254
255rotbb:
256  %sub = sub i32 32, %b
257  %shl = shl i32 %a, %sub
258  %shr = lshr i32 %a, %b
259  %or = or i32 %shl, %shr
260  br label %end
261
262end:
263  %cond = phi i32 [ %b, %entry ], [ %or, %rotbb ]
264  ret i32 %cond
265}
266
267; Negative test - too many phi ops.
268
269define i32 @not_rotr_2(i32 %a, i32 %b, i32 %c) {
270; CHECK-LABEL: @not_rotr_2(
271; CHECK-NEXT:  entry:
272; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0
273; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]]
274; CHECK:       rotbb:
275; CHECK-NEXT:    [[SUB:%.*]] = sub i32 32, [[B]]
276; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]
277; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[A]], [[B]]
278; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHL]], [[SHR]]
279; CHECK-NEXT:    [[CMP42:%.*]] = icmp ugt i32 [[OR]], 42
280; CHECK-NEXT:    br i1 [[CMP42]], label [[END]], label [[BOGUS:%.*]]
281; CHECK:       bogus:
282; CHECK-NEXT:    br label [[END]]
283; CHECK:       end:
284; CHECK-NEXT:    [[COND:%.*]] = phi i32 [ [[A]], [[ENTRY:%.*]] ], [ [[OR]], [[ROTBB]] ], [ [[C:%.*]], [[BOGUS]] ]
285; CHECK-NEXT:    ret i32 [[COND]]
286;
287entry:
288  %cmp = icmp eq i32 %b, 0
289  br i1 %cmp, label %end, label %rotbb
290
291rotbb:
292  %sub = sub i32 32, %b
293  %shl = shl i32 %a, %sub
294  %shr = lshr i32 %a, %b
295  %or = or i32 %shl, %shr
296  %cmp42 = icmp ugt i32 %or, 42
297  br i1 %cmp42, label %end, label %bogus
298
299bogus:
300  br label %end
301
302end:
303  %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ], [ %c, %bogus ]
304  ret i32 %cond
305}
306
307; Negative test - wrong cmp (but this should match?).
308
309define i32 @not_rotr_3(i32 %a, i32 %b) {
310; CHECK-LABEL: @not_rotr_3(
311; CHECK-NEXT:  entry:
312; CHECK-NEXT:    [[CMP:%.*]] = icmp sle i32 [[B:%.*]], 0
313; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]]
314; CHECK:       rotbb:
315; CHECK-NEXT:    [[SUB:%.*]] = sub i32 32, [[B]]
316; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]
317; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[A]], [[B]]
318; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHL]], [[SHR]]
319; CHECK-NEXT:    br label [[END]]
320; CHECK:       end:
321; CHECK-NEXT:    [[COND:%.*]] = phi i32 [ [[A]], [[ENTRY:%.*]] ], [ [[OR]], [[ROTBB]] ]
322; CHECK-NEXT:    ret i32 [[COND]]
323;
324entry:
325  %cmp = icmp sle i32 %b, 0
326  br i1 %cmp, label %end, label %rotbb
327
328rotbb:
329  %sub = sub i32 32, %b
330  %shl = shl i32 %a, %sub
331  %shr = lshr i32 %a, %b
332  %or = or i32 %shl, %shr
333  br label %end
334
335end:
336  %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ]
337  ret i32 %cond
338}
339
340; Negative test - wrong shift.
341
342define i32 @not_rotr_4(i32 %a, i32 %b) {
343; CHECK-LABEL: @not_rotr_4(
344; CHECK-NEXT:  entry:
345; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0
346; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]]
347; CHECK:       rotbb:
348; CHECK-NEXT:    [[SUB:%.*]] = sub i32 32, [[B]]
349; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]
350; CHECK-NEXT:    [[SHR:%.*]] = ashr i32 [[A]], [[B]]
351; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHL]], [[SHR]]
352; CHECK-NEXT:    br label [[END]]
353; CHECK:       end:
354; CHECK-NEXT:    [[COND:%.*]] = phi i32 [ [[A]], [[ENTRY:%.*]] ], [ [[OR]], [[ROTBB]] ]
355; CHECK-NEXT:    ret i32 [[COND]]
356;
357entry:
358  %cmp = icmp eq i32 %b, 0
359  br i1 %cmp, label %end, label %rotbb
360
361rotbb:
362  %sub = sub i32 32, %b
363  %shl = shl i32 %a, %sub
364  %shr = ashr i32 %a, %b
365  %or = or i32 %shl, %shr
366  br label %end
367
368end:
369  %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ]
370  ret i32 %cond
371}
372
373; Negative test - wrong shift for rotate (but can be folded to a generic funnel shift).
374
375define i32 @not_rotr_5(i32 %a, i32 %b) {
376; CHECK-LABEL: @not_rotr_5(
377; CHECK-NEXT:  entry:
378; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0
379; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]]
380; CHECK:       rotbb:
381; CHECK-NEXT:    br label [[END]]
382; CHECK:       end:
383; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.fshr.i32(i32 [[B]], i32 [[A:%.*]], i32 [[B]])
384; CHECK-NEXT:    ret i32 [[TMP0]]
385;
386entry:
387  %cmp = icmp eq i32 %b, 0
388  br i1 %cmp, label %end, label %rotbb
389
390rotbb:
391  %sub = sub i32 32, %b
392  %shl = shl i32 %b, %sub
393  %shr = lshr i32 %a, %b
394  %or = or i32 %shl, %shr
395  br label %end
396
397end:
398  %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ]
399  ret i32 %cond
400}
401
402; Negative test - wrong sub.
403
404define i32 @not_rotr_6(i32 %a, i32 %b) {
405; CHECK-LABEL: @not_rotr_6(
406; CHECK-NEXT:  entry:
407; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0
408; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]]
409; CHECK:       rotbb:
410; CHECK-NEXT:    [[SUB:%.*]] = sub i32 8, [[B]]
411; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]
412; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[A]], [[B]]
413; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHL]], [[SHR]]
414; CHECK-NEXT:    br label [[END]]
415; CHECK:       end:
416; CHECK-NEXT:    [[COND:%.*]] = phi i32 [ [[A]], [[ENTRY:%.*]] ], [ [[OR]], [[ROTBB]] ]
417; CHECK-NEXT:    ret i32 [[COND]]
418;
419entry:
420  %cmp = icmp eq i32 %b, 0
421  br i1 %cmp, label %end, label %rotbb
422
423rotbb:
424  %sub = sub i32 8, %b
425  %shl = shl i32 %a, %sub
426  %shr = lshr i32 %a, %b
427  %or = or i32 %shl, %shr
428  br label %end
429
430end:
431  %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ]
432  ret i32 %cond
433}
434
435; Negative test - extra use. Technically, we could transform this
436; because it doesn't increase the instruction count, but we're
437; being cautious not to cause a potential perf pessimization for
438; targets that do not have a rotate instruction.
439
440define i32 @could_be_rotr(i32 %a, i32 %b, ptr %p) {
441; CHECK-LABEL: @could_be_rotr(
442; CHECK-NEXT:  entry:
443; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0
444; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]]
445; CHECK:       rotbb:
446; CHECK-NEXT:    [[SUB:%.*]] = sub i32 32, [[B]]
447; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]
448; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[A]], [[B]]
449; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHL]], [[SHR]]
450; CHECK-NEXT:    store i32 [[OR]], ptr [[P:%.*]], align 4
451; CHECK-NEXT:    br label [[END]]
452; CHECK:       end:
453; CHECK-NEXT:    [[COND:%.*]] = phi i32 [ [[A]], [[ENTRY:%.*]] ], [ [[OR]], [[ROTBB]] ]
454; CHECK-NEXT:    ret i32 [[COND]]
455;
456entry:
457  %cmp = icmp eq i32 %b, 0
458  br i1 %cmp, label %end, label %rotbb
459
460rotbb:
461  %sub = sub i32 32, %b
462  %shl = shl i32 %a, %sub
463  %shr = lshr i32 %a, %b
464  %or = or i32 %shl, %shr
465  store i32 %or, ptr %p
466  br label %end
467
468end:
469  %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ]
470  ret i32 %cond
471}
472
473