1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -passes=aggressive-instcombine -S | FileCheck %s
4 define i32 @fshl(i32 %a, i32 %b, i32 %c) {
7 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
8 ; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]
10 ; CHECK-NEXT: br label [[END]]
12 ; CHECK-NEXT: [[TMP0:%.*]] = freeze i32 [[B:%.*]]
13 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A:%.*]], i32 [[TMP0]], i32 [[C]])
14 ; CHECK-NEXT: ret i32 [[TMP1]]
17 %cmp = icmp eq i32 %c, 0
18 br i1 %cmp, label %end, label %fshbb
22 %shr = lshr i32 %b, %sub
24 %or = or i32 %shr, %shl
28 %cond = phi i32 [ %or, %fshbb ], [ %a, %entry ]
32 define i32 @fshl_commute_phi(i32 %a, i32 %b, i32 %c) {
33 ; CHECK-LABEL: @fshl_commute_phi(
35 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
36 ; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]
38 ; CHECK-NEXT: br label [[END]]
40 ; CHECK-NEXT: [[TMP0:%.*]] = freeze i32 [[B:%.*]]
41 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A:%.*]], i32 [[TMP0]], i32 [[C]])
42 ; CHECK-NEXT: ret i32 [[TMP1]]
45 %cmp = icmp eq i32 %c, 0
46 br i1 %cmp, label %end, label %fshbb
50 %shr = lshr i32 %b, %sub
52 %or = or i32 %shr, %shl
56 %cond = phi i32 [ %a, %entry ], [ %or, %fshbb ]
60 define i32 @fshl_commute_or(i32 %a, i32 %b, i32 %c) {
61 ; CHECK-LABEL: @fshl_commute_or(
63 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
64 ; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]
66 ; CHECK-NEXT: br label [[END]]
68 ; CHECK-NEXT: [[TMP0:%.*]] = freeze i32 [[B:%.*]]
69 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A:%.*]], i32 [[TMP0]], i32 [[C]])
70 ; CHECK-NEXT: ret i32 [[TMP1]]
73 %cmp = icmp eq i32 %c, 0
74 br i1 %cmp, label %end, label %fshbb
78 %shr = lshr i32 %b, %sub
80 %or = or i32 %shl, %shr
84 %cond = phi i32 [ %a, %entry ], [ %or, %fshbb ]
88 ; Verify that the intrinsic is inserted into a valid position.
90 define i32 @fshl_insert_valid_location(i32 %a, i32 %b, i32 %c) {
91 ; CHECK-LABEL: @fshl_insert_valid_location(
93 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
94 ; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]
96 ; CHECK-NEXT: br label [[END]]
98 ; CHECK-NEXT: [[OTHER:%.*]] = phi i32 [ 1, [[FSHBB]] ], [ 2, [[ENTRY:%.*]] ]
99 ; CHECK-NEXT: [[TMP0:%.*]] = freeze i32 [[B:%.*]]
100 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A:%.*]], i32 [[TMP0]], i32 [[C]])
101 ; CHECK-NEXT: [[RES:%.*]] = or i32 [[TMP1]], [[OTHER]]
102 ; CHECK-NEXT: ret i32 [[RES]]
105 %cmp = icmp eq i32 %c, 0
106 br i1 %cmp, label %end, label %fshbb
109 %sub = sub i32 32, %c
110 %shr = lshr i32 %b, %sub
111 %shl = shl i32 %a, %c
112 %or = or i32 %shr, %shl
116 %cond = phi i32 [ %or, %fshbb ], [ %a, %entry ]
117 %other = phi i32 [ 1, %fshbb ], [ 2, %entry ]
118 %res = or i32 %cond, %other
122 define i32 @fshr(i32 %a, i32 %b, i32 %c) {
123 ; CHECK-LABEL: @fshr(
125 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
126 ; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]
128 ; CHECK-NEXT: br label [[END]]
130 ; CHECK-NEXT: [[TMP0:%.*]] = freeze i32 [[A:%.*]]
131 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.fshr.i32(i32 [[TMP0]], i32 [[B:%.*]], i32 [[C]])
132 ; CHECK-NEXT: ret i32 [[TMP1]]
135 %cmp = icmp eq i32 %c, 0
136 br i1 %cmp, label %end, label %fshbb
139 %sub = sub i32 32, %c
140 %shl = shl i32 %a, %sub
141 %shr = lshr i32 %b, %c
142 %or = or i32 %shr, %shl
146 %cond = phi i32 [ %or, %fshbb ], [ %b, %entry ]
150 define i32 @fshr_commute_phi(i32 %a, i32 %b, i32 %c) {
151 ; CHECK-LABEL: @fshr_commute_phi(
153 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
154 ; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]
156 ; CHECK-NEXT: br label [[END]]
158 ; CHECK-NEXT: [[TMP0:%.*]] = freeze i32 [[A:%.*]]
159 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.fshr.i32(i32 [[TMP0]], i32 [[B:%.*]], i32 [[C]])
160 ; CHECK-NEXT: ret i32 [[TMP1]]
163 %cmp = icmp eq i32 %c, 0
164 br i1 %cmp, label %end, label %fshbb
167 %sub = sub i32 32, %c
168 %shl = shl i32 %a, %sub
169 %shr = lshr i32 %b, %c
170 %or = or i32 %shr, %shl
174 %cond = phi i32 [ %b, %entry ], [ %or, %fshbb ]
178 define i32 @fshr_commute_or(i32 %a, i32 %b, i32 %c) {
179 ; CHECK-LABEL: @fshr_commute_or(
181 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
182 ; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]
184 ; CHECK-NEXT: br label [[END]]
186 ; CHECK-NEXT: [[TMP0:%.*]] = freeze i32 [[A:%.*]]
187 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.fshr.i32(i32 [[TMP0]], i32 [[B:%.*]], i32 [[C]])
188 ; CHECK-NEXT: ret i32 [[TMP1]]
191 %cmp = icmp eq i32 %c, 0
192 br i1 %cmp, label %end, label %fshbb
195 %sub = sub i32 32, %c
196 %shl = shl i32 %a, %sub
197 %shr = lshr i32 %b, %c
198 %or = or i32 %shl, %shr
202 %cond = phi i32 [ %b, %entry ], [ %or, %fshbb ]
206 ; Negative test - non-power-of-2 might require urem expansion in the backend.
208 define i12 @could_be_fshr_weird_type(i12 %a, i12 %b, i12 %c) {
209 ; CHECK-LABEL: @could_be_fshr_weird_type(
211 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i12 [[C:%.*]], 0
212 ; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]
214 ; CHECK-NEXT: [[SUB:%.*]] = sub i12 12, [[C]]
215 ; CHECK-NEXT: [[SHL:%.*]] = shl i12 [[A:%.*]], [[SUB]]
216 ; CHECK-NEXT: [[SHR:%.*]] = lshr i12 [[B:%.*]], [[C]]
217 ; CHECK-NEXT: [[OR:%.*]] = or i12 [[SHL]], [[SHR]]
218 ; CHECK-NEXT: br label [[END]]
220 ; CHECK-NEXT: [[COND:%.*]] = phi i12 [ [[B]], [[ENTRY:%.*]] ], [ [[OR]], [[FSHBB]] ]
221 ; CHECK-NEXT: ret i12 [[COND]]
224 %cmp = icmp eq i12 %c, 0
225 br i1 %cmp, label %end, label %fshbb
228 %sub = sub i12 12, %c
229 %shl = shl i12 %a, %sub
230 %shr = lshr i12 %b, %c
231 %or = or i12 %shl, %shr
235 %cond = phi i12 [ %b, %entry ], [ %or, %fshbb ]
239 ; Negative test - wrong phi ops.
241 define i32 @not_fshr_1(i32 %a, i32 %b, i32 %c) {
242 ; CHECK-LABEL: @not_fshr_1(
244 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
245 ; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]
247 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[C]]
248 ; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]
249 ; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[B:%.*]], [[C]]
250 ; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]]
251 ; CHECK-NEXT: br label [[END]]
253 ; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[C]], [[ENTRY:%.*]] ], [ [[OR]], [[FSHBB]] ]
254 ; CHECK-NEXT: ret i32 [[COND]]
257 %cmp = icmp eq i32 %c, 0
258 br i1 %cmp, label %end, label %fshbb
261 %sub = sub i32 32, %c
262 %shl = shl i32 %a, %sub
263 %shr = lshr i32 %b, %c
264 %or = or i32 %shl, %shr
268 %cond = phi i32 [ %c, %entry ], [ %or, %fshbb ]
272 ; Negative test - too many phi ops.
274 define i32 @not_fshr_2(i32 %a, i32 %b, i32 %c, i32 %d) {
275 ; CHECK-LABEL: @not_fshr_2(
277 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
278 ; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]
280 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[C]]
281 ; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]
282 ; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[B:%.*]], [[C]]
283 ; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]]
284 ; CHECK-NEXT: [[CMP42:%.*]] = icmp ugt i32 [[OR]], 42
285 ; CHECK-NEXT: br i1 [[CMP42]], label [[END]], label [[BOGUS:%.*]]
287 ; CHECK-NEXT: br label [[END]]
289 ; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[B]], [[ENTRY:%.*]] ], [ [[OR]], [[FSHBB]] ], [ [[D:%.*]], [[BOGUS]] ]
290 ; CHECK-NEXT: ret i32 [[COND]]
293 %cmp = icmp eq i32 %c, 0
294 br i1 %cmp, label %end, label %fshbb
297 %sub = sub i32 32, %c
298 %shl = shl i32 %a, %sub
299 %shr = lshr i32 %b, %c
300 %or = or i32 %shl, %shr
301 %cmp42 = icmp ugt i32 %or, 42
302 br i1 %cmp42, label %end, label %bogus
308 %cond = phi i32 [ %b, %entry ], [ %or, %fshbb ], [ %d, %bogus ]
312 ; Negative test - wrong cmp (but this should match?).
314 define i32 @not_fshr_3(i32 %a, i32 %b, i32 %c) {
315 ; CHECK-LABEL: @not_fshr_3(
317 ; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[C:%.*]], 0
318 ; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]
320 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[C]]
321 ; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]
322 ; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[B:%.*]], [[C]]
323 ; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]]
324 ; CHECK-NEXT: br label [[END]]
326 ; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[B]], [[ENTRY:%.*]] ], [ [[OR]], [[FSHBB]] ]
327 ; CHECK-NEXT: ret i32 [[COND]]
330 %cmp = icmp sle i32 %c, 0
331 br i1 %cmp, label %end, label %fshbb
334 %sub = sub i32 32, %c
335 %shl = shl i32 %a, %sub
336 %shr = lshr i32 %b, %c
337 %or = or i32 %shl, %shr
341 %cond = phi i32 [ %b, %entry ], [ %or, %fshbb ]
345 ; Negative test - wrong shift.
347 define i32 @not_fshr_4(i32 %a, i32 %b, i32 %c) {
348 ; CHECK-LABEL: @not_fshr_4(
350 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
351 ; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]
353 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[C]]
354 ; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]
355 ; CHECK-NEXT: [[SHR:%.*]] = ashr i32 [[B:%.*]], [[C]]
356 ; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]]
357 ; CHECK-NEXT: br label [[END]]
359 ; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[B]], [[ENTRY:%.*]] ], [ [[OR]], [[FSHBB]] ]
360 ; CHECK-NEXT: ret i32 [[COND]]
363 %cmp = icmp eq i32 %c, 0
364 br i1 %cmp, label %end, label %fshbb
367 %sub = sub i32 32, %c
368 %shl = shl i32 %a, %sub
369 %shr = ashr i32 %b, %c
370 %or = or i32 %shl, %shr
374 %cond = phi i32 [ %b, %entry ], [ %or, %fshbb ]
378 ; Negative test - wrong shift for rotate (but can be folded to a generic funnel shift).
380 define i32 @not_fshr_5(i32 %a, i32 %b, i32 %c) {
381 ; CHECK-LABEL: @not_fshr_5(
383 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
384 ; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]
386 ; CHECK-NEXT: br label [[END]]
388 ; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.fshr.i32(i32 [[C]], i32 [[B:%.*]], i32 [[C]])
389 ; CHECK-NEXT: ret i32 [[TMP0]]
392 %cmp = icmp eq i32 %c, 0
393 br i1 %cmp, label %end, label %fshbb
396 %sub = sub i32 32, %c
397 %shl = shl i32 %c, %sub
398 %shr = lshr i32 %b, %c
399 %or = or i32 %shl, %shr
403 %cond = phi i32 [ %b, %entry ], [ %or, %fshbb ]
407 ; Negative test - wrong sub.
409 define i32 @not_fshr_6(i32 %a, i32 %b, i32 %c) {
410 ; CHECK-LABEL: @not_fshr_6(
412 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
413 ; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]
415 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 8, [[C]]
416 ; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]
417 ; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[B:%.*]], [[C]]
418 ; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]]
419 ; CHECK-NEXT: br label [[END]]
421 ; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[B]], [[ENTRY:%.*]] ], [ [[OR]], [[FSHBB]] ]
422 ; CHECK-NEXT: ret i32 [[COND]]
425 %cmp = icmp eq i32 %c, 0
426 br i1 %cmp, label %end, label %fshbb
430 %shl = shl i32 %a, %sub
431 %shr = lshr i32 %b, %c
432 %or = or i32 %shl, %shr
436 %cond = phi i32 [ %b, %entry ], [ %or, %fshbb ]
440 ; Negative test - extra use. Technically, we could transform this
441 ; because it doesn't increase the instruction count, but we're
442 ; being cautious not to cause a potential perf pessimization for
443 ; targets that do not have a fshate instruction.
445 define i32 @could_be_fshr(i32 %a, i32 %b, i32 %c, ptr %p) {
446 ; CHECK-LABEL: @could_be_fshr(
448 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
449 ; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[FSHBB:%.*]]
451 ; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[C]]
452 ; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]
453 ; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[B:%.*]], [[C]]
454 ; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]]
455 ; CHECK-NEXT: store i32 [[OR]], ptr [[P:%.*]], align 4
456 ; CHECK-NEXT: br label [[END]]
458 ; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[B]], [[ENTRY:%.*]] ], [ [[OR]], [[FSHBB]] ]
459 ; CHECK-NEXT: ret i32 [[COND]]
462 %cmp = icmp eq i32 %c, 0
463 br i1 %cmp, label %end, label %fshbb
466 %sub = sub i32 32, %c
467 %shl = shl i32 %a, %sub
468 %shr = lshr i32 %b, %c
469 %or = or i32 %shl, %shr
470 store i32 %or, ptr %p
474 %cond = phi i32 [ %b, %entry ], [ %or, %fshbb ]
478 ; PR48068 - Ensure we don't fold a funnel shift that depends on a shift value that
479 ; can't be hoisted out of a basic block.
480 @a = global i32 0, align 4
484 define i32 @PR48068() {
485 ; CHECK-LABEL: @PR48068(
487 ; CHECK-NEXT: [[CALL:%.*]] = call i32 @i()
488 ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr @a, align 4
489 ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[TMP0]], 0
490 ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
492 ; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[CALL]], [[TMP0]]
493 ; CHECK-NEXT: [[CALL_I:%.*]] = call i32 @f()
494 ; CHECK-NEXT: [[SUB_I:%.*]] = sub nsw i32 32, [[TMP0]]
495 ; CHECK-NEXT: [[SHR_I:%.*]] = lshr i32 [[CALL_I]], [[SUB_I]]
496 ; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR_I]]
497 ; CHECK-NEXT: br label [[IF_END]]
499 ; CHECK-NEXT: [[H_0:%.*]] = phi i32 [ [[OR]], [[IF_THEN]] ], [ [[CALL]], [[ENTRY:%.*]] ]
500 ; CHECK-NEXT: ret i32 [[H_0]]
503 %call = call i32 @i()
504 %0 = load i32, ptr @a, align 4
505 %tobool.not = icmp eq i32 %0, 0
506 br i1 %tobool.not, label %if.end, label %if.then
508 if.then: ; preds = %entry
509 %shl = shl i32 %call, %0
510 %call.i = call i32 @f()
511 %sub.i = sub nsw i32 32, %0
512 %shr.i = lshr i32 %call.i, %sub.i
513 %or = or i32 %shl, %shr.i
516 if.end: ; preds = %if.then, %entry
517 %h.0 = phi i32 [ %or, %if.then ], [ %call, %entry ]