; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -S -instcombine < %s | FileCheck %s declare void @foo() declare void @bar() declare void @baz() declare void @qux() declare void @quux() declare i1 @geni1() declare void @usei32(i32) declare void @usei32i32agg({ i32, i32 }) ; Most basic test - diamond structure define { i32, i32 } @test0({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) { ; CHECK-LABEL: @test0( ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] ; CHECK: left: ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: right: ; CHECK-NEXT: call void @bar() ; CHECK-NEXT: br label [[END]] ; CHECK: end: ; CHECK-NEXT: [[AGG_LEFT_PN:%.*]] = phi { i32, i32 } [ [[AGG_LEFT:%.*]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ] ; CHECK-NEXT: call void @baz() ; CHECK-NEXT: ret { i32, i32 } [[AGG_LEFT_PN]] ; entry: br i1 %c, label %left, label %right left: %i0 = extractvalue { i32, i32 } %agg_left, 0 %i2 = extractvalue { i32, i32 } %agg_left, 1 call void @foo() br label %end right: %i3 = extractvalue { i32, i32 } %agg_right, 0 %i4 = extractvalue { i32, i32 } %agg_right, 1 call void @bar() br label %end end: %i5 = phi i32 [ %i0, %left ], [ %i3, %right ] %i6 = phi i32 [ %i2, %left ], [ %i4, %right ] call void @baz() %i7 = insertvalue { i32, i32 } undef, i32 %i5, 0 %i8 = insertvalue { i32, i32 } %i7, i32 %i6, 1 ret { i32, i32 } %i8 } ; Second element is coming from wrong aggregate define { i32, i32 } @negative_test1({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) { ; CHECK-LABEL: @negative_test1( ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] ; CHECK: left: ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: right: ; CHECK-NEXT: call void @bar() ; CHECK-NEXT: br label [[END]] ; CHECK: end: ; CHECK-NEXT: [[AGG_LEFT_PN:%.*]] = phi { i32, i32 } [ [[AGG_LEFT:%.*]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ] ; CHECK-NEXT: [[AGG_RIGHT_PN:%.*]] = phi { i32, i32 } [ [[AGG_RIGHT]], [[LEFT]] ], [ [[AGG_LEFT]], [[RIGHT]] ] ; CHECK-NEXT: [[I6:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT_PN]], 1 ; CHECK-NEXT: [[I5:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT_PN]], 0 ; CHECK-NEXT: call void @baz() ; CHECK-NEXT: [[I7:%.*]] = insertvalue { i32, i32 } undef, i32 [[I5]], 0 ; CHECK-NEXT: [[I8:%.*]] = insertvalue { i32, i32 } [[I7]], i32 [[I6]], 1 ; CHECK-NEXT: ret { i32, i32 } [[I8]] ; entry: %i0 = extractvalue { i32, i32 } %agg_left, 0 %i2 = extractvalue { i32, i32 } %agg_left, 1 %i3 = extractvalue { i32, i32 } %agg_right, 0 %i4 = extractvalue { i32, i32 } %agg_right, 1 br i1 %c, label %left, label %right left: call void @foo() br label %end right: call void @bar() br label %end end: %i5 = phi i32 [ %i0, %left ], [ %i3, %right ] %i6 = phi i32 [ %i4, %left ], [ %i2, %right ] call void @baz() %i7 = insertvalue { i32, i32 } undef, i32 %i5, 0 %i8 = insertvalue { i32, i32 } %i7, i32 %i6, 1 ret { i32, i32 } %i8 } ; When coming from %left, elements are swapped define { i32, i32 } @negative_test2({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) { ; CHECK-LABEL: @negative_test2( ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] ; CHECK: left: ; CHECK-NEXT: [[I2:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 1 ; CHECK-NEXT: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT]], 0 ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: right: ; CHECK-NEXT: [[I4:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT:%.*]], 1 ; CHECK-NEXT: [[I3:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT]], 0 ; CHECK-NEXT: call void @bar() ; CHECK-NEXT: br label [[END]] ; CHECK: end: ; CHECK-NEXT: [[I5:%.*]] = phi i32 [ [[I2]], [[LEFT]] ], [ [[I3]], [[RIGHT]] ] ; CHECK-NEXT: [[I6:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I4]], [[RIGHT]] ] ; CHECK-NEXT: call void @baz() ; CHECK-NEXT: [[I7:%.*]] = insertvalue { i32, i32 } undef, i32 [[I5]], 0 ; CHECK-NEXT: [[I8:%.*]] = insertvalue { i32, i32 } [[I7]], i32 [[I6]], 1 ; CHECK-NEXT: ret { i32, i32 } [[I8]] ; entry: %i0 = extractvalue { i32, i32 } %agg_left, 0 %i2 = extractvalue { i32, i32 } %agg_left, 1 %i3 = extractvalue { i32, i32 } %agg_right, 0 %i4 = extractvalue { i32, i32 } %agg_right, 1 br i1 %c, label %left, label %right left: call void @foo() br label %end right: call void @bar() br label %end end: %i5 = phi i32 [ %i2, %left ], [ %i3, %right ] %i6 = phi i32 [ %i0, %left ], [ %i4, %right ] call void @baz() %i7 = insertvalue { i32, i32 } undef, i32 %i5, 0 %i8 = insertvalue { i32, i32 } %i7, i32 %i6, 1 ret { i32, i32 } %i8 } ; FIXME: we should probably be able to handle multiple levels of PHI indirection define { i32, i32 } @test3({ i32, i32 } %agg_00, { i32, i32 } %agg_01, { i32, i32 } %agg_10, i1 %c0, i1 %c1) { ; CHECK-LABEL: @test3( ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[C0:%.*]], label [[BB0_DISPATCH:%.*]], label [[BB10:%.*]] ; CHECK: bb0.dispatch: ; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB00:%.*]], label [[BB01:%.*]] ; CHECK: bb00: ; CHECK-NEXT: br label [[BB0_MERGE:%.*]] ; CHECK: bb01: ; CHECK-NEXT: br label [[BB0_MERGE]] ; CHECK: bb0.merge: ; CHECK-NEXT: [[AGG_00_PN:%.*]] = phi { i32, i32 } [ [[AGG_00:%.*]], [[BB00]] ], [ [[AGG_01:%.*]], [[BB01]] ] ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: bb10: ; CHECK-NEXT: br label [[END]] ; CHECK: end: ; CHECK-NEXT: [[AGG_00_PN_PN:%.*]] = phi { i32, i32 } [ [[AGG_00_PN]], [[BB0_MERGE]] ], [ [[AGG_10:%.*]], [[BB10]] ] ; CHECK-NEXT: call void @baz() ; CHECK-NEXT: ret { i32, i32 } [[AGG_00_PN_PN]] ; entry: br i1 %c0, label %bb0.dispatch, label %bb10 bb0.dispatch: br i1 %c1, label %bb00, label %bb01 bb00: %i0 = extractvalue { i32, i32 } %agg_00, 0 %i1 = extractvalue { i32, i32 } %agg_00, 1 br label %bb0.merge bb01: %i2 = extractvalue { i32, i32 } %agg_01, 0 %i3 = extractvalue { i32, i32 } %agg_01, 1 br label %bb0.merge bb0.merge: %i4 = phi i32 [ %i0, %bb00 ], [ %i2, %bb01 ] %i5 = phi i32 [ %i1, %bb00 ], [ %i3, %bb01 ] br label %end bb10: %i6 = extractvalue { i32, i32 } %agg_10, 0 %i7 = extractvalue { i32, i32 } %agg_10, 1 br label %end end: %i8 = phi i32 [ %i4, %bb0.merge ], [ %i6, %bb10 ] %i9 = phi i32 [ %i5, %bb0.merge ], [ %i7, %bb10 ] call void @baz() %i10 = insertvalue { i32, i32 } undef, i32 %i8, 0 %i11 = insertvalue { i32, i32 } %i10, i32 %i9, 1 ret { i32, i32 } %i11 } ; Not sure what should happen for cycles. define { i32, i32 } @test4({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c0) { ; CHECK-LABEL: @test4( ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[C0:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] ; CHECK: left: ; CHECK-NEXT: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 0 ; CHECK-NEXT: [[I2:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT]], 1 ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: br label [[MIDDLE:%.*]] ; CHECK: right: ; CHECK-NEXT: [[I3:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT:%.*]], 0 ; CHECK-NEXT: [[I4:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT]], 1 ; CHECK-NEXT: call void @bar() ; CHECK-NEXT: br label [[MIDDLE]] ; CHECK: middle: ; CHECK-NEXT: [[I5:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I3]], [[RIGHT]] ], [ [[I5]], [[MIDDLE]] ] ; CHECK-NEXT: [[I6:%.*]] = phi i32 [ [[I2]], [[LEFT]] ], [ [[I4]], [[RIGHT]] ], [ [[I6]], [[MIDDLE]] ] ; CHECK-NEXT: call void @baz() ; CHECK-NEXT: [[C1:%.*]] = call i1 @geni1() ; CHECK-NEXT: br i1 [[C1]], label [[END:%.*]], label [[MIDDLE]] ; CHECK: end: ; CHECK-NEXT: [[I7:%.*]] = insertvalue { i32, i32 } undef, i32 [[I5]], 0 ; CHECK-NEXT: [[I8:%.*]] = insertvalue { i32, i32 } [[I7]], i32 [[I6]], 1 ; CHECK-NEXT: ret { i32, i32 } [[I8]] ; entry: br i1 %c0, label %left, label %right left: %i0 = extractvalue { i32, i32 } %agg_left, 0 %i2 = extractvalue { i32, i32 } %agg_left, 1 call void @foo() br label %middle right: %i3 = extractvalue { i32, i32 } %agg_right, 0 %i4 = extractvalue { i32, i32 } %agg_right, 1 call void @bar() br label %middle middle: %i5 = phi i32 [ %i0, %left ], [ %i3, %right ], [ %i5, %middle ] %i6 = phi i32 [ %i2, %left ], [ %i4, %right ], [ %i6, %middle ] call void @baz() %i7 = insertvalue { i32, i32 } undef, i32 %i5, 0 %i8 = insertvalue { i32, i32 } %i7, i32 %i6, 1 %c1 = call i1 @geni1() br i1 %c1, label %end, label %middle end: ret { i32, i32 } %i8 } ; But here since we start without an explicit self-cycle, we already manage to fold it. define { i32, i32 } @test5({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c0) { ; CHECK-LABEL: @test5( ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[C0:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] ; CHECK: left: ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: br label [[MIDDLE:%.*]] ; CHECK: right: ; CHECK-NEXT: call void @bar() ; CHECK-NEXT: br label [[MIDDLE]] ; CHECK: middle: ; CHECK-NEXT: [[AGG_LEFT_PN:%.*]] = phi { i32, i32 } [ [[AGG_LEFT:%.*]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ], [ [[AGG_LEFT_PN]], [[MIDDLE]] ] ; CHECK-NEXT: call void @baz() ; CHECK-NEXT: [[C1:%.*]] = call i1 @geni1() ; CHECK-NEXT: br i1 [[C1]], label [[END:%.*]], label [[MIDDLE]] ; CHECK: end: ; CHECK-NEXT: ret { i32, i32 } [[AGG_LEFT_PN]] ; entry: br i1 %c0, label %left, label %right left: %i0 = extractvalue { i32, i32 } %agg_left, 0 %i2 = extractvalue { i32, i32 } %agg_left, 1 call void @foo() br label %middle right: %i3 = extractvalue { i32, i32 } %agg_right, 0 %i4 = extractvalue { i32, i32 } %agg_right, 1 call void @bar() br label %middle middle: %i5 = phi i32 [ %i0, %left ], [ %i3, %right ], [ %i9, %middle ] %i6 = phi i32 [ %i2, %left ], [ %i4, %right ], [ %i10, %middle ] call void @baz() %i7 = insertvalue { i32, i32 } undef, i32 %i5, 0 %i8 = insertvalue { i32, i32 } %i7, i32 %i6, 1 %i9 = extractvalue { i32, i32 } %i8, 0 %i10 = extractvalue { i32, i32 } %i8, 1 %c1 = call i1 @geni1() br i1 %c1, label %end, label %middle end: ret { i32, i32 } %i8 } ; Diamond structure, but with "padding" block before the use. define { i32, i32 } @test6({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c0, i1 %c1) { ; CHECK-LABEL: @test6( ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[C0:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] ; CHECK: left: ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: br label [[MERGE:%.*]] ; CHECK: right: ; CHECK-NEXT: call void @bar() ; CHECK-NEXT: br label [[MERGE]] ; CHECK: merge: ; CHECK-NEXT: [[AGG_LEFT_PN:%.*]] = phi { i32, i32 } [ [[AGG_LEFT:%.*]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ] ; CHECK-NEXT: call void @baz() ; CHECK-NEXT: br i1 [[C1:%.*]], label [[END:%.*]], label [[PASSTHROUGH:%.*]] ; CHECK: passthrough: ; CHECK-NEXT: call void @qux() ; CHECK-NEXT: br label [[END]] ; CHECK: end: ; CHECK-NEXT: call void @quux() ; CHECK-NEXT: ret { i32, i32 } [[AGG_LEFT_PN]] ; entry: br i1 %c0, label %left, label %right left: %i0 = extractvalue { i32, i32 } %agg_left, 0 %i2 = extractvalue { i32, i32 } %agg_left, 1 call void @foo() br label %merge right: %i3 = extractvalue { i32, i32 } %agg_right, 0 %i4 = extractvalue { i32, i32 } %agg_right, 1 call void @bar() br label %merge merge: %i5 = phi i32 [ %i0, %left ], [ %i3, %right ] %i6 = phi i32 [ %i2, %left ], [ %i4, %right ] call void @baz() br i1 %c1, label %end, label %passthrough passthrough: call void @qux() br label %end end: call void @quux() %i7 = insertvalue { i32, i32 } undef, i32 %i5, 0 %i8 = insertvalue { i32, i32 } %i7, i32 %i6, 1 ret { i32, i32 } %i8 } ; All the definitions of the aggregate elements must happen in the same block. define { i32, i32 } @negative_test7({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c0, i1 %c1) { ; CHECK-LABEL: @negative_test7( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 0 ; CHECK-NEXT: call void @usei32(i32 [[I0]]) ; CHECK-NEXT: br i1 [[C0:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] ; CHECK: left: ; CHECK-NEXT: [[I1:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT]], 1 ; CHECK-NEXT: call void @usei32(i32 [[I1]]) ; CHECK-NEXT: br label [[MERGE:%.*]] ; CHECK: right: ; CHECK-NEXT: [[I2:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT:%.*]], 1 ; CHECK-NEXT: call void @usei32(i32 [[I2]]) ; CHECK-NEXT: br label [[MERGE]] ; CHECK: merge: ; CHECK-NEXT: [[I3:%.*]] = phi i32 [ [[I1]], [[LEFT]] ], [ [[I2]], [[RIGHT]] ] ; CHECK-NEXT: call void @bar() ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: end: ; CHECK-NEXT: call void @baz() ; CHECK-NEXT: [[I7:%.*]] = insertvalue { i32, i32 } undef, i32 [[I0]], 0 ; CHECK-NEXT: [[I8:%.*]] = insertvalue { i32, i32 } [[I7]], i32 [[I3]], 1 ; CHECK-NEXT: ret { i32, i32 } [[I8]] ; entry: %i0 = extractvalue { i32, i32 } %agg_left, 0 call void @usei32(i32 %i0) br i1 %c0, label %left, label %right left: %i1 = extractvalue { i32, i32 } %agg_left, 1 call void @usei32(i32 %i1) br label %merge right: %i2 = extractvalue { i32, i32 } %agg_right, 1 call void @usei32(i32 %i2) br label %merge merge: %i3 = phi i32 [ %i1, %left ], [ %i2, %right ] call void @bar() br label %end end: call void @baz() %i7 = insertvalue { i32, i32 } undef, i32 %i0, 0 %i8 = insertvalue { i32, i32 } %i7, i32 %i3, 1 ret { i32, i32 } %i8 } ; Most basic test - diamond structure, but with a switch, which results in multiple duplicate predecessors define { i32, i32 } @test8({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c, i32 %val_left, i32 %val_right) { ; CHECK-LABEL: @test8( ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] ; CHECK: left: ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: switch i32 [[VAL_LEFT:%.*]], label [[IMPOSSIBLE:%.*]] [ ; CHECK-NEXT: i32 -42, label [[END:%.*]] ; CHECK-NEXT: i32 42, label [[END]] ; CHECK-NEXT: ] ; CHECK: right: ; CHECK-NEXT: call void @bar() ; CHECK-NEXT: switch i32 [[VAL_RIGHT:%.*]], label [[IMPOSSIBLE]] [ ; CHECK-NEXT: i32 42, label [[END]] ; CHECK-NEXT: i32 -42, label [[END]] ; CHECK-NEXT: ] ; CHECK: impossible: ; CHECK-NEXT: unreachable ; CHECK: end: ; CHECK-NEXT: [[AGG_LEFT_PN:%.*]] = phi { i32, i32 } [ [[AGG_LEFT:%.*]], [[LEFT]] ], [ [[AGG_LEFT]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ], [ [[AGG_RIGHT]], [[RIGHT]] ] ; CHECK-NEXT: call void @baz() ; CHECK-NEXT: ret { i32, i32 } [[AGG_LEFT_PN]] ; entry: br i1 %c, label %left, label %right left: %i0 = extractvalue { i32, i32 } %agg_left, 0 %i2 = extractvalue { i32, i32 } %agg_left, 1 call void @foo() switch i32 %val_left, label %impossible [ i32 -42, label %end i32 42, label %end ] right: %i3 = extractvalue { i32, i32 } %agg_right, 0 %i4 = extractvalue { i32, i32 } %agg_right, 1 call void @bar() switch i32 %val_right, label %impossible [ i32 42, label %end i32 -42, label %end ] impossible: unreachable end: %i5 = phi i32 [ %i0, %left ], [ %i0, %left ], [ %i3, %right ], [ %i3, %right ] %i6 = phi i32 [ %i2, %left ], [ %i2, %left ], [ %i4, %right ], [ %i4, %right ] call void @baz() %i7 = insertvalue { i32, i32 } undef, i32 %i5, 0 %i8 = insertvalue { i32, i32 } %i7, i32 %i6, 1 ret { i32, i32 } %i8 } ; The insertion of first element could have been split/hoisted into the predecessors. define { i32, i32 } @test9({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) { ; CHECK-LABEL: @test9( ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] ; CHECK: left: ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: right: ; CHECK-NEXT: call void @bar() ; CHECK-NEXT: br label [[END]] ; CHECK: end: ; CHECK-NEXT: [[AGG_LEFT_PN:%.*]] = phi { i32, i32 } [ [[AGG_LEFT:%.*]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ] ; CHECK-NEXT: call void @baz() ; CHECK-NEXT: ret { i32, i32 } [[AGG_LEFT_PN]] ; entry: br i1 %c, label %left, label %right left: %i0 = extractvalue { i32, i32 } %agg_left, 0 %i1 = extractvalue { i32, i32 } %agg_left, 1 %i2 = insertvalue { i32, i32 } undef, i32 %i0, 0 call void @foo() br label %end right: %i3 = extractvalue { i32, i32 } %agg_right, 0 %i4 = extractvalue { i32, i32 } %agg_right, 1 %i5 = insertvalue { i32, i32 } undef, i32 %i3, 0 call void @bar() br label %end end: %i6 = phi { i32, i32 } [ %i2, %left ], [ %i5, %right ] %i7 = phi i32 [ %i1, %left ], [ %i4, %right ] call void @baz() %i8 = insertvalue { i32, i32 } %i6, i32 %i7, 1 ret { i32, i32 } %i8 }