; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=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
}