1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

[NFC][InstCombine] Tests for PHI-of-insertvalue's

Currently we don't do anything about these,
neither in InstCombine, nor in SimplifyCFG's sinking.
These happen exceedingly rarely, but i've seen them in the cases where
PHI-aware aggregate reconstruction would have fired if not for them.
This commit is contained in:
Roman Lebedev 2020-08-20 19:16:48 +03:00
parent efb79ce4ea
commit c0a69dfec4
2 changed files with 275 additions and 0 deletions

View File

@ -477,3 +477,52 @@ end:
%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: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 0
; CHECK-NEXT: [[I1:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT]], 1
; CHECK-NEXT: [[I2:%.*]] = insertvalue { i32, i32 } undef, i32 [[I0]], 0
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: right:
; CHECK-NEXT: [[I3:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT:%.*]], 0
; CHECK-NEXT: [[I4:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT]], 1
; CHECK-NEXT: [[I5:%.*]] = insertvalue { i32, i32 } undef, i32 [[I3]], 0
; CHECK-NEXT: call void @bar()
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[I6:%.*]] = phi { i32, i32 } [ [[I2]], [[LEFT]] ], [ [[I5]], [[RIGHT]] ]
; CHECK-NEXT: [[I7:%.*]] = phi i32 [ [[I1]], [[LEFT]] ], [ [[I4]], [[RIGHT]] ]
; CHECK-NEXT: call void @baz()
; CHECK-NEXT: [[I8:%.*]] = insertvalue { i32, i32 } [[I6]], i32 [[I7]], 1
; CHECK-NEXT: ret { i32, i32 } [[I8]]
;
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
}

View File

@ -0,0 +1,226 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -instcombine < %s | FileCheck %s
declare void @usei32i32agg({ i32, i32 })
; If we have a phi of insertvalues, we can sink it,
; Here, we only need a PHI for inserted values.
define { i32, i32 } @test0({ i32, i32 } %agg, i32 %val_left, i32 %val_right, i1 %c) {
; CHECK-LABEL: @test0(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
; CHECK: left:
; CHECK-NEXT: [[I0:%.*]] = insertvalue { i32, i32 } [[AGG:%.*]], i32 [[VAL_LEFT:%.*]], 0
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: right:
; CHECK-NEXT: [[I1:%.*]] = insertvalue { i32, i32 } [[AGG]], i32 [[VAL_RIGHT:%.*]], 0
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[R:%.*]] = phi { i32, i32 } [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]
; CHECK-NEXT: ret { i32, i32 } [[R]]
;
entry:
br i1 %c, label %left, label %right
left:
%i0 = insertvalue { i32, i32 } %agg, i32 %val_left, 0
br label %end
right:
%i1 = insertvalue { i32, i32 } %agg, i32 %val_right, 0
br label %end
end:
%r = phi { i32, i32 } [ %i0, %left ], [ %i1, %right ]
ret { i32, i32 } %r
}
; But only if the insertvalues have no extra uses
define { i32, i32 } @test1_extrause0({ i32, i32 } %agg, i32 %val_left, i32 %val_right, i1 %c) {
; CHECK-LABEL: @test1_extrause0(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
; CHECK: left:
; CHECK-NEXT: [[I0:%.*]] = insertvalue { i32, i32 } [[AGG:%.*]], i32 [[VAL_LEFT:%.*]], 0
; CHECK-NEXT: call void @usei32i32agg({ i32, i32 } [[I0]])
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: right:
; CHECK-NEXT: [[I1:%.*]] = insertvalue { i32, i32 } [[AGG]], i32 [[VAL_RIGHT:%.*]], 0
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[R:%.*]] = phi { i32, i32 } [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]
; CHECK-NEXT: ret { i32, i32 } [[R]]
;
entry:
br i1 %c, label %left, label %right
left:
%i0 = insertvalue { i32, i32 } %agg, i32 %val_left, 0
call void @usei32i32agg({ i32, i32 } %i0 )
br label %end
right:
%i1 = insertvalue { i32, i32 } %agg, i32 %val_right, 0
br label %end
end:
%r = phi { i32, i32 } [ %i0, %left ], [ %i1, %right ]
ret { i32, i32 } %r
}
define { i32, i32 } @test2_extrause1({ i32, i32 } %agg, i32 %val_left, i32 %val_right, i1 %c) {
; CHECK-LABEL: @test2_extrause1(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
; CHECK: left:
; CHECK-NEXT: [[I0:%.*]] = insertvalue { i32, i32 } [[AGG:%.*]], i32 [[VAL_LEFT:%.*]], 0
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: right:
; CHECK-NEXT: [[I1:%.*]] = insertvalue { i32, i32 } [[AGG]], i32 [[VAL_RIGHT:%.*]], 0
; CHECK-NEXT: call void @usei32i32agg({ i32, i32 } [[I1]])
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[R:%.*]] = phi { i32, i32 } [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]
; CHECK-NEXT: ret { i32, i32 } [[R]]
;
entry:
br i1 %c, label %left, label %right
left:
%i0 = insertvalue { i32, i32 } %agg, i32 %val_left, 0
br label %end
right:
%i1 = insertvalue { i32, i32 } %agg, i32 %val_right, 0
call void @usei32i32agg({ i32, i32 } %i1 )
br label %end
end:
%r = phi { i32, i32 } [ %i0, %left ], [ %i1, %right ]
ret { i32, i32 } %r
}
define { i32, i32 } @test3_extrause2({ i32, i32 } %agg, i32 %val_left, i32 %val_right, i1 %c) {
; CHECK-LABEL: @test3_extrause2(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
; CHECK: left:
; CHECK-NEXT: [[I0:%.*]] = insertvalue { i32, i32 } [[AGG:%.*]], i32 [[VAL_LEFT:%.*]], 0
; CHECK-NEXT: call void @usei32i32agg({ i32, i32 } [[I0]])
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: right:
; CHECK-NEXT: [[I1:%.*]] = insertvalue { i32, i32 } [[AGG]], i32 [[VAL_RIGHT:%.*]], 0
; CHECK-NEXT: call void @usei32i32agg({ i32, i32 } [[I1]])
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[R:%.*]] = phi { i32, i32 } [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]
; CHECK-NEXT: ret { i32, i32 } [[R]]
;
entry:
br i1 %c, label %left, label %right
left:
%i0 = insertvalue { i32, i32 } %agg, i32 %val_left, 0
call void @usei32i32agg({ i32, i32 } %i0 )
br label %end
right:
%i1 = insertvalue { i32, i32 } %agg, i32 %val_right, 0
call void @usei32i32agg({ i32, i32 } %i1 )
br label %end
end:
%r = phi { i32, i32 } [ %i0, %left ], [ %i1, %right ]
ret { i32, i32 } %r
}
; Here, we only need a PHI for base aggregate
define { i32, i32 } @test4({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i32 %val, i1 %c) {
; CHECK-LABEL: @test4(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
; CHECK: left:
; CHECK-NEXT: [[I0:%.*]] = insertvalue { i32, i32 } [[AGG_LEFT:%.*]], i32 [[VAL:%.*]], 0
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: right:
; CHECK-NEXT: [[I1:%.*]] = insertvalue { i32, i32 } [[AGG_RIGHT:%.*]], i32 [[VAL]], 0
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[R:%.*]] = phi { i32, i32 } [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]
; CHECK-NEXT: ret { i32, i32 } [[R]]
;
entry:
br i1 %c, label %left, label %right
left:
%i0 = insertvalue { i32, i32 } %agg_left, i32 %val, 0
br label %end
right:
%i1 = insertvalue { i32, i32 } %agg_right, i32 %val, 0
br label %end
end:
%r = phi { i32, i32 } [ %i0, %left ], [ %i1, %right ]
ret { i32, i32 } %r
}
; Here, we need a PHI for both the base and the inserted value
define { i32, i32 } @test5({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i32 %val_left, i32 %val_right, i1 %c) {
; CHECK-LABEL: @test5(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
; CHECK: left:
; CHECK-NEXT: [[I0:%.*]] = insertvalue { i32, i32 } [[AGG_LEFT:%.*]], i32 [[VAL_LEFT:%.*]], 0
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: right:
; CHECK-NEXT: [[I1:%.*]] = insertvalue { i32, i32 } [[AGG_RIGHT:%.*]], i32 [[VAL_RIGHT:%.*]], 0
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[R:%.*]] = phi { i32, i32 } [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]
; CHECK-NEXT: ret { i32, i32 } [[R]]
;
entry:
br i1 %c, label %left, label %right
left:
%i0 = insertvalue { i32, i32 } %agg_left, i32 %val_left, 0
br label %end
right:
%i1 = insertvalue { i32, i32 } %agg_right, i32 %val_right, 0
br label %end
end:
%r = phi { i32, i32 } [ %i0, %left ], [ %i1, %right ]
ret { i32, i32 } %r
}
; But the indicies must match
define { i32, i32 } @test6({ i32, i32 } %agg, i32 %val_left, i32 %val_right, i1 %c) {
; CHECK-LABEL: @test6(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
; CHECK: left:
; CHECK-NEXT: [[I0:%.*]] = insertvalue { i32, i32 } [[AGG:%.*]], i32 [[VAL_LEFT:%.*]], 0
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: right:
; CHECK-NEXT: [[I1:%.*]] = insertvalue { i32, i32 } [[AGG]], i32 [[VAL_RIGHT:%.*]], 1
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[R:%.*]] = phi { i32, i32 } [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]
; CHECK-NEXT: ret { i32, i32 } [[R]]
;
entry:
br i1 %c, label %left, label %right
left:
%i0 = insertvalue { i32, i32 } %agg, i32 %val_left, 0
br label %end
right:
%i1 = insertvalue { i32, i32 } %agg, i32 %val_right, 1
br label %end
end:
%r = phi { i32, i32 } [ %i0, %left ], [ %i1, %right ]
ret { i32, i32 } %r
}