
Function foldAggregateConstructionIntoAggregateReuse can fold insertvalue(phi(extractvalue(src1), extractvalue(src2))) into phi(src1, src2) when we can find source aggregates in all predecessors. This patch extends it to handle following case insertvalue(phi(extractvalue(src1), elm2)) into phi(src1, insertvalue(elm2)) with the condition that the predecessor without source aggregate has only one successor.
507 lines
17 KiB
LLVM
507 lines
17 KiB
LLVM
; 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, and new insertvalue is created.
|
|
; From right side the old aggregate can be directly reused.
|
|
define { i32, i32 } @positive_test2({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) {
|
|
; CHECK-LABEL: @positive_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: [[TMP0:%.*]] = insertvalue { i32, i32 } poison, i32 [[I2]], 0
|
|
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i32, i32 } [[TMP0]], i32 [[I0]], 1
|
|
; CHECK-NEXT: br label [[END:%.*]]
|
|
; CHECK: right:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label [[END]]
|
|
; CHECK: end:
|
|
; CHECK-NEXT: [[I8_MERGED:%.*]] = phi { i32, i32 } [ [[TMP1]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ]
|
|
; CHECK-NEXT: call void @baz()
|
|
; CHECK-NEXT: ret { i32, i32 } [[I8_MERGED]]
|
|
;
|
|
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
|
|
}
|