1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -S -instcombine < %s | FileCheck %s
12 declare void @usei32(i32)
13 declare void @usei32i32agg({ i32, i32 })
15 ; Most basic test - diamond structure
16 define { i32, i32 } @test0({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) {
17 ; CHECK-LABEL: @test0(
19 ; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
21 ; CHECK-NEXT: call void @foo()
22 ; CHECK-NEXT: br label [[END:%.*]]
24 ; CHECK-NEXT: call void @bar()
25 ; CHECK-NEXT: br label [[END]]
27 ; CHECK-NEXT: [[AGG_LEFT_PN:%.*]] = phi { i32, i32 } [ [[AGG_LEFT:%.*]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ]
28 ; CHECK-NEXT: call void @baz()
29 ; CHECK-NEXT: ret { i32, i32 } [[AGG_LEFT_PN]]
32 br i1 %c, label %left, label %right
35 %i0 = extractvalue { i32, i32 } %agg_left, 0
36 %i2 = extractvalue { i32, i32 } %agg_left, 1
41 %i3 = extractvalue { i32, i32 } %agg_right, 0
42 %i4 = extractvalue { i32, i32 } %agg_right, 1
47 %i5 = phi i32 [ %i0, %left ], [ %i3, %right ]
48 %i6 = phi i32 [ %i2, %left ], [ %i4, %right ]
50 %i7 = insertvalue { i32, i32 } undef, i32 %i5, 0
51 %i8 = insertvalue { i32, i32 } %i7, i32 %i6, 1
55 ; Second element is coming from wrong aggregate
56 define { i32, i32 } @negative_test1({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) {
57 ; CHECK-LABEL: @negative_test1(
59 ; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
61 ; CHECK-NEXT: call void @foo()
62 ; CHECK-NEXT: br label [[END:%.*]]
64 ; CHECK-NEXT: call void @bar()
65 ; CHECK-NEXT: br label [[END]]
67 ; CHECK-NEXT: [[AGG_LEFT_PN:%.*]] = phi { i32, i32 } [ [[AGG_LEFT:%.*]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ]
68 ; CHECK-NEXT: [[AGG_RIGHT_PN:%.*]] = phi { i32, i32 } [ [[AGG_RIGHT]], [[LEFT]] ], [ [[AGG_LEFT]], [[RIGHT]] ]
69 ; CHECK-NEXT: [[I6:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT_PN]], 1
70 ; CHECK-NEXT: [[I5:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT_PN]], 0
71 ; CHECK-NEXT: call void @baz()
72 ; CHECK-NEXT: [[I7:%.*]] = insertvalue { i32, i32 } undef, i32 [[I5]], 0
73 ; CHECK-NEXT: [[I8:%.*]] = insertvalue { i32, i32 } [[I7]], i32 [[I6]], 1
74 ; CHECK-NEXT: ret { i32, i32 } [[I8]]
77 %i0 = extractvalue { i32, i32 } %agg_left, 0
78 %i2 = extractvalue { i32, i32 } %agg_left, 1
79 %i3 = extractvalue { i32, i32 } %agg_right, 0
80 %i4 = extractvalue { i32, i32 } %agg_right, 1
81 br i1 %c, label %left, label %right
92 %i5 = phi i32 [ %i0, %left ], [ %i3, %right ]
93 %i6 = phi i32 [ %i4, %left ], [ %i2, %right ]
95 %i7 = insertvalue { i32, i32 } undef, i32 %i5, 0
96 %i8 = insertvalue { i32, i32 } %i7, i32 %i6, 1
100 ; When coming from %left, elements are swapped
101 define { i32, i32 } @negative_test2({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) {
102 ; CHECK-LABEL: @negative_test2(
104 ; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
106 ; CHECK-NEXT: [[I2:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 1
107 ; CHECK-NEXT: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT]], 0
108 ; CHECK-NEXT: call void @foo()
109 ; CHECK-NEXT: br label [[END:%.*]]
111 ; CHECK-NEXT: [[I4:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT:%.*]], 1
112 ; CHECK-NEXT: [[I3:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT]], 0
113 ; CHECK-NEXT: call void @bar()
114 ; CHECK-NEXT: br label [[END]]
116 ; CHECK-NEXT: [[I5:%.*]] = phi i32 [ [[I2]], [[LEFT]] ], [ [[I3]], [[RIGHT]] ]
117 ; CHECK-NEXT: [[I6:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I4]], [[RIGHT]] ]
118 ; CHECK-NEXT: call void @baz()
119 ; CHECK-NEXT: [[I7:%.*]] = insertvalue { i32, i32 } undef, i32 [[I5]], 0
120 ; CHECK-NEXT: [[I8:%.*]] = insertvalue { i32, i32 } [[I7]], i32 [[I6]], 1
121 ; CHECK-NEXT: ret { i32, i32 } [[I8]]
124 %i0 = extractvalue { i32, i32 } %agg_left, 0
125 %i2 = extractvalue { i32, i32 } %agg_left, 1
126 %i3 = extractvalue { i32, i32 } %agg_right, 0
127 %i4 = extractvalue { i32, i32 } %agg_right, 1
128 br i1 %c, label %left, label %right
139 %i5 = phi i32 [ %i2, %left ], [ %i3, %right ]
140 %i6 = phi i32 [ %i0, %left ], [ %i4, %right ]
142 %i7 = insertvalue { i32, i32 } undef, i32 %i5, 0
143 %i8 = insertvalue { i32, i32 } %i7, i32 %i6, 1
147 ; FIXME: we should probably be able to handle multiple levels of PHI indirection
148 define { i32, i32 } @test3({ i32, i32 } %agg_00, { i32, i32 } %agg_01, { i32, i32 } %agg_10, i1 %c0, i1 %c1) {
149 ; CHECK-LABEL: @test3(
151 ; CHECK-NEXT: br i1 [[C0:%.*]], label [[BB0_DISPATCH:%.*]], label [[BB10:%.*]]
152 ; CHECK: bb0.dispatch:
153 ; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB00:%.*]], label [[BB01:%.*]]
155 ; CHECK-NEXT: br label [[BB0_MERGE:%.*]]
157 ; CHECK-NEXT: br label [[BB0_MERGE]]
159 ; CHECK-NEXT: [[AGG_00_PN:%.*]] = phi { i32, i32 } [ [[AGG_00:%.*]], [[BB00]] ], [ [[AGG_01:%.*]], [[BB01]] ]
160 ; CHECK-NEXT: br label [[END:%.*]]
162 ; CHECK-NEXT: br label [[END]]
164 ; CHECK-NEXT: [[AGG_00_PN_PN:%.*]] = phi { i32, i32 } [ [[AGG_00_PN]], [[BB0_MERGE]] ], [ [[AGG_10:%.*]], [[BB10]] ]
165 ; CHECK-NEXT: call void @baz()
166 ; CHECK-NEXT: ret { i32, i32 } [[AGG_00_PN_PN]]
169 br i1 %c0, label %bb0.dispatch, label %bb10
172 br i1 %c1, label %bb00, label %bb01
175 %i0 = extractvalue { i32, i32 } %agg_00, 0
176 %i1 = extractvalue { i32, i32 } %agg_00, 1
180 %i2 = extractvalue { i32, i32 } %agg_01, 0
181 %i3 = extractvalue { i32, i32 } %agg_01, 1
185 %i4 = phi i32 [ %i0, %bb00 ], [ %i2, %bb01 ]
186 %i5 = phi i32 [ %i1, %bb00 ], [ %i3, %bb01 ]
190 %i6 = extractvalue { i32, i32 } %agg_10, 0
191 %i7 = extractvalue { i32, i32 } %agg_10, 1
195 %i8 = phi i32 [ %i4, %bb0.merge ], [ %i6, %bb10 ]
196 %i9 = phi i32 [ %i5, %bb0.merge ], [ %i7, %bb10 ]
198 %i10 = insertvalue { i32, i32 } undef, i32 %i8, 0
199 %i11 = insertvalue { i32, i32 } %i10, i32 %i9, 1
200 ret { i32, i32 } %i11
203 ; Not sure what should happen for cycles.
204 define { i32, i32 } @test4({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c0) {
205 ; CHECK-LABEL: @test4(
207 ; CHECK-NEXT: br i1 [[C0:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
209 ; CHECK-NEXT: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 0
210 ; CHECK-NEXT: [[I2:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT]], 1
211 ; CHECK-NEXT: call void @foo()
212 ; CHECK-NEXT: br label [[MIDDLE:%.*]]
214 ; CHECK-NEXT: [[I3:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT:%.*]], 0
215 ; CHECK-NEXT: [[I4:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT]], 1
216 ; CHECK-NEXT: call void @bar()
217 ; CHECK-NEXT: br label [[MIDDLE]]
219 ; CHECK-NEXT: [[I5:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I3]], [[RIGHT]] ], [ [[I5]], [[MIDDLE]] ]
220 ; CHECK-NEXT: [[I6:%.*]] = phi i32 [ [[I2]], [[LEFT]] ], [ [[I4]], [[RIGHT]] ], [ [[I6]], [[MIDDLE]] ]
221 ; CHECK-NEXT: call void @baz()
222 ; CHECK-NEXT: [[C1:%.*]] = call i1 @geni1()
223 ; CHECK-NEXT: br i1 [[C1]], label [[END:%.*]], label [[MIDDLE]]
225 ; CHECK-NEXT: [[I7:%.*]] = insertvalue { i32, i32 } undef, i32 [[I5]], 0
226 ; CHECK-NEXT: [[I8:%.*]] = insertvalue { i32, i32 } [[I7]], i32 [[I6]], 1
227 ; CHECK-NEXT: ret { i32, i32 } [[I8]]
230 br i1 %c0, label %left, label %right
233 %i0 = extractvalue { i32, i32 } %agg_left, 0
234 %i2 = extractvalue { i32, i32 } %agg_left, 1
239 %i3 = extractvalue { i32, i32 } %agg_right, 0
240 %i4 = extractvalue { i32, i32 } %agg_right, 1
245 %i5 = phi i32 [ %i0, %left ], [ %i3, %right ], [ %i5, %middle ]
246 %i6 = phi i32 [ %i2, %left ], [ %i4, %right ], [ %i6, %middle ]
248 %i7 = insertvalue { i32, i32 } undef, i32 %i5, 0
249 %i8 = insertvalue { i32, i32 } %i7, i32 %i6, 1
250 %c1 = call i1 @geni1()
251 br i1 %c1, label %end, label %middle
257 ; But here since we start without an explicit self-cycle, we already manage to fold it.
258 define { i32, i32 } @test5({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c0) {
259 ; CHECK-LABEL: @test5(
261 ; CHECK-NEXT: br i1 [[C0:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
263 ; CHECK-NEXT: call void @foo()
264 ; CHECK-NEXT: br label [[MIDDLE:%.*]]
266 ; CHECK-NEXT: call void @bar()
267 ; CHECK-NEXT: br label [[MIDDLE]]
269 ; CHECK-NEXT: [[AGG_LEFT_PN:%.*]] = phi { i32, i32 } [ [[AGG_LEFT:%.*]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ], [ [[AGG_LEFT_PN]], [[MIDDLE]] ]
270 ; CHECK-NEXT: call void @baz()
271 ; CHECK-NEXT: [[C1:%.*]] = call i1 @geni1()
272 ; CHECK-NEXT: br i1 [[C1]], label [[END:%.*]], label [[MIDDLE]]
274 ; CHECK-NEXT: ret { i32, i32 } [[AGG_LEFT_PN]]
277 br i1 %c0, label %left, label %right
280 %i0 = extractvalue { i32, i32 } %agg_left, 0
281 %i2 = extractvalue { i32, i32 } %agg_left, 1
286 %i3 = extractvalue { i32, i32 } %agg_right, 0
287 %i4 = extractvalue { i32, i32 } %agg_right, 1
292 %i5 = phi i32 [ %i0, %left ], [ %i3, %right ], [ %i9, %middle ]
293 %i6 = phi i32 [ %i2, %left ], [ %i4, %right ], [ %i10, %middle ]
295 %i7 = insertvalue { i32, i32 } undef, i32 %i5, 0
296 %i8 = insertvalue { i32, i32 } %i7, i32 %i6, 1
297 %i9 = extractvalue { i32, i32 } %i8, 0
298 %i10 = extractvalue { i32, i32 } %i8, 1
299 %c1 = call i1 @geni1()
300 br i1 %c1, label %end, label %middle
306 ; Diamond structure, but with "padding" block before the use.
307 define { i32, i32 } @test6({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c0, i1 %c1) {
308 ; CHECK-LABEL: @test6(
310 ; CHECK-NEXT: br i1 [[C0:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
312 ; CHECK-NEXT: call void @foo()
313 ; CHECK-NEXT: br label [[MERGE:%.*]]
315 ; CHECK-NEXT: call void @bar()
316 ; CHECK-NEXT: br label [[MERGE]]
318 ; CHECK-NEXT: [[AGG_LEFT_PN:%.*]] = phi { i32, i32 } [ [[AGG_LEFT:%.*]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ]
319 ; CHECK-NEXT: call void @baz()
320 ; CHECK-NEXT: br i1 [[C1:%.*]], label [[END:%.*]], label [[PASSTHROUGH:%.*]]
321 ; CHECK: passthrough:
322 ; CHECK-NEXT: call void @qux()
323 ; CHECK-NEXT: br label [[END]]
325 ; CHECK-NEXT: call void @quux()
326 ; CHECK-NEXT: ret { i32, i32 } [[AGG_LEFT_PN]]
329 br i1 %c0, label %left, label %right
332 %i0 = extractvalue { i32, i32 } %agg_left, 0
333 %i2 = extractvalue { i32, i32 } %agg_left, 1
338 %i3 = extractvalue { i32, i32 } %agg_right, 0
339 %i4 = extractvalue { i32, i32 } %agg_right, 1
344 %i5 = phi i32 [ %i0, %left ], [ %i3, %right ]
345 %i6 = phi i32 [ %i2, %left ], [ %i4, %right ]
347 br i1 %c1, label %end, label %passthrough
355 %i7 = insertvalue { i32, i32 } undef, i32 %i5, 0
356 %i8 = insertvalue { i32, i32 } %i7, i32 %i6, 1
360 ; All the definitions of the aggregate elements must happen in the same block.
361 define { i32, i32 } @negative_test7({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c0, i1 %c1) {
362 ; CHECK-LABEL: @negative_test7(
364 ; CHECK-NEXT: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 0
365 ; CHECK-NEXT: call void @usei32(i32 [[I0]])
366 ; CHECK-NEXT: br i1 [[C0:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
368 ; CHECK-NEXT: [[I1:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT]], 1
369 ; CHECK-NEXT: call void @usei32(i32 [[I1]])
370 ; CHECK-NEXT: br label [[MERGE:%.*]]
372 ; CHECK-NEXT: [[I2:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT:%.*]], 1
373 ; CHECK-NEXT: call void @usei32(i32 [[I2]])
374 ; CHECK-NEXT: br label [[MERGE]]
376 ; CHECK-NEXT: [[I3:%.*]] = phi i32 [ [[I1]], [[LEFT]] ], [ [[I2]], [[RIGHT]] ]
377 ; CHECK-NEXT: call void @bar()
378 ; CHECK-NEXT: br label [[END:%.*]]
380 ; CHECK-NEXT: call void @baz()
381 ; CHECK-NEXT: [[I7:%.*]] = insertvalue { i32, i32 } undef, i32 [[I0]], 0
382 ; CHECK-NEXT: [[I8:%.*]] = insertvalue { i32, i32 } [[I7]], i32 [[I3]], 1
383 ; CHECK-NEXT: ret { i32, i32 } [[I8]]
386 %i0 = extractvalue { i32, i32 } %agg_left, 0
387 call void @usei32(i32 %i0)
388 br i1 %c0, label %left, label %right
391 %i1 = extractvalue { i32, i32 } %agg_left, 1
392 call void @usei32(i32 %i1)
396 %i2 = extractvalue { i32, i32 } %agg_right, 1
397 call void @usei32(i32 %i2)
401 %i3 = phi i32 [ %i1, %left ], [ %i2, %right ]
407 %i7 = insertvalue { i32, i32 } undef, i32 %i0, 0
408 %i8 = insertvalue { i32, i32 } %i7, i32 %i3, 1
412 ; Most basic test - diamond structure, but with a switch, which results in multiple duplicate predecessors
413 define { i32, i32 } @test8({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c, i32 %val_left, i32 %val_right) {
414 ; CHECK-LABEL: @test8(
416 ; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
418 ; CHECK-NEXT: call void @foo()
419 ; CHECK-NEXT: switch i32 [[VAL_LEFT:%.*]], label [[IMPOSSIBLE:%.*]] [
420 ; CHECK-NEXT: i32 -42, label [[END:%.*]]
421 ; CHECK-NEXT: i32 42, label [[END]]
424 ; CHECK-NEXT: call void @bar()
425 ; CHECK-NEXT: switch i32 [[VAL_RIGHT:%.*]], label [[IMPOSSIBLE]] [
426 ; CHECK-NEXT: i32 42, label [[END]]
427 ; CHECK-NEXT: i32 -42, label [[END]]
430 ; CHECK-NEXT: unreachable
432 ; CHECK-NEXT: [[AGG_LEFT_PN:%.*]] = phi { i32, i32 } [ [[AGG_LEFT:%.*]], [[LEFT]] ], [ [[AGG_LEFT]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ], [ [[AGG_RIGHT]], [[RIGHT]] ]
433 ; CHECK-NEXT: call void @baz()
434 ; CHECK-NEXT: ret { i32, i32 } [[AGG_LEFT_PN]]
437 br i1 %c, label %left, label %right
440 %i0 = extractvalue { i32, i32 } %agg_left, 0
441 %i2 = extractvalue { i32, i32 } %agg_left, 1
443 switch i32 %val_left, label %impossible [
449 %i3 = extractvalue { i32, i32 } %agg_right, 0
450 %i4 = extractvalue { i32, i32 } %agg_right, 1
452 switch i32 %val_right, label %impossible [
461 %i5 = phi i32 [ %i0, %left ], [ %i0, %left ], [ %i3, %right ], [ %i3, %right ]
462 %i6 = phi i32 [ %i2, %left ], [ %i2, %left ], [ %i4, %right ], [ %i4, %right ]
464 %i7 = insertvalue { i32, i32 } undef, i32 %i5, 0
465 %i8 = insertvalue { i32, i32 } %i7, i32 %i6, 1
469 ; The insertion of first element could have been split/hoisted into the predecessors.
470 define { i32, i32 } @test9({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) {
471 ; CHECK-LABEL: @test9(
473 ; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
475 ; CHECK-NEXT: call void @foo()
476 ; CHECK-NEXT: br label [[END:%.*]]
478 ; CHECK-NEXT: call void @bar()
479 ; CHECK-NEXT: br label [[END]]
481 ; CHECK-NEXT: [[AGG_LEFT_PN:%.*]] = phi { i32, i32 } [ [[AGG_LEFT:%.*]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ]
482 ; CHECK-NEXT: call void @baz()
483 ; CHECK-NEXT: ret { i32, i32 } [[AGG_LEFT_PN]]
486 br i1 %c, label %left, label %right
489 %i0 = extractvalue { i32, i32 } %agg_left, 0
490 %i1 = extractvalue { i32, i32 } %agg_left, 1
491 %i2 = insertvalue { i32, i32 } undef, i32 %i0, 0
496 %i3 = extractvalue { i32, i32 } %agg_right, 0
497 %i4 = extractvalue { i32, i32 } %agg_right, 1
498 %i5 = insertvalue { i32, i32 } undef, i32 %i3, 0
503 %i6 = phi { i32, i32 } [ %i2, %left ], [ %i5, %right ]
504 %i7 = phi i32 [ %i1, %left ], [ %i4, %right ]
506 %i8 = insertvalue { i32, i32 } %i6, i32 %i7, 1