mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-01 05:01:59 +01:00
d6cd909866
While since D86306 we do it's sibling fold for `insertvalue`, we should also do this for `extractvalue`'s. And unlike that one, the results here are, quite honestly, shocking, as it can be observed here on vanilla llvm test-suite + RawSpeed results: ``` | statistic name | baseline | proposed | Δ | % | |%| | |----------------------------------------------------|-----------|-----------|--------:|--------:|-------:| | asm-printer.EmittedInsts | 7945095 | 7942507 | -2588 | -0.03% | 0.03% | | assembler.ObjectBytes | 273209920 | 273069800 | -140120 | -0.05% | 0.05% | | early-cse.NumCSE | 2183363 | 2183398 | 35 | 0.00% | 0.00% | | early-cse.NumSimplify | 541847 | 550017 | 8170 | 1.51% | 1.51% | | instcombine.NumAggregateReconstructionsSimplified | 2139 | 108 | -2031 | -94.95% | 94.95% | | instcombine.NumCombined | 3601364 | 3635448 | 34084 | 0.95% | 0.95% | | instcombine.NumConstProp | 27153 | 27157 | 4 | 0.01% | 0.01% | | instcombine.NumDeadInst | 1694521 | 1765022 | 70501 | 4.16% | 4.16% | | instcombine.NumPHIsOfExtractValues | 0 | 37546 | 37546 | 0.00% | 0.00% | | instcombine.NumSunkInst | 63158 | 63686 | 528 | 0.84% | 0.84% | | instcount.NumBrInst | 874304 | 871857 | -2447 | -0.28% | 0.28% | | instcount.NumCallInst | 1757657 | 1758402 | 745 | 0.04% | 0.04% | | instcount.NumExtractValueInst | 45623 | 11483 | -34140 | -74.83% | 74.83% | | instcount.NumInsertValueInst | 4983 | 580 | -4403 | -88.36% | 88.36% | | instcount.NumInvokeInst | 61018 | 59478 | -1540 | -2.52% | 2.52% | | instcount.NumLandingPadInst | 35334 | 34215 | -1119 | -3.17% | 3.17% | | instcount.NumPHIInst | 344428 | 331116 | -13312 | -3.86% | 3.86% | | instcount.NumRetInst | 100773 | 100772 | -1 | 0.00% | 0.00% | | instcount.TotalBlocks | 1081154 | 1077166 | -3988 | -0.37% | 0.37% | | instcount.TotalFuncs | 101443 | 101442 | -1 | 0.00% | 0.00% | | instcount.TotalInsts | 8890201 | 8833747 | -56454 | -0.64% | 0.64% | | instsimplify.NumSimplified | 75822 | 75707 | -115 | -0.15% | 0.15% | | simplifycfg.NumHoistCommonCode | 24203 | 24197 | -6 | -0.02% | 0.02% | | simplifycfg.NumHoistCommonInstrs | 48201 | 48195 | -6 | -0.01% | 0.01% | | simplifycfg.NumInvokes | 2785 | 4298 | 1513 | 54.33% | 54.33% | | simplifycfg.NumSimpl | 997332 | 1018189 | 20857 | 2.09% | 2.09% | | simplifycfg.NumSinkCommonCode | 7088 | 6464 | -624 | -8.80% | 8.80% | | simplifycfg.NumSinkCommonInstrs | 15117 | 14021 | -1096 | -7.25% | 7.25% | ``` ... which tells us that this new fold fires whopping 38k times, increasing the amount of SimplifyCFG's `invoke`->`call` transforms by +54% (+1513) (again, D85787 did that last time), decreasing total instruction count by -0.64% (-56454), and sharply decreasing count of `insertvalue`'s (-88.36%, i.e. 9 times less) and `extractvalue`'s (-74.83%, i.e. four times less). This causes geomean -0.01% binary size decrease http://llvm-compile-time-tracker.com/compare.php?from=4d5ca22b8adfb6643466e4e9f48ba14bb48938bc&to=97dacca0111cb2ae678204e52a3cee00e3a69208&stat=size-text and, ignoring `O0-g`, is a geomean -0.01%..-0.05% compile-time improvement http://llvm-compile-time-tracker.com/compare.php?from=4d5ca22b8adfb6643466e4e9f48ba14bb48938bc&to=97dacca0111cb2ae678204e52a3cee00e3a69208&stat=instructions The other thing that tells is, is that while this is a massive win for `invoke`->`call` transform `InstCombinerImpl::foldAggregateConstructionIntoAggregateReuse()` fold, which is supposed to be dealing with such aggregate reconstructions, fires a lot less now. There are two reasons why: 1. After this fold, as it can be seen in tests, we may (will) end up with trivially redundant PHI nodes. We don't CSE them in InstCombine presently, which means that EarlyCSE needs to run and then InstCombine rerun. 2. But then, EarlyCSE not only manages to fold such redundant PHI's, it also sees that the extract-insert chain recreates the original aggregate, and replaces it with the original aggregate. The take-aways are 1. We maybe should do most trivial, same-BB PHI CSE in InstCombine 2. I need to check if what other patterns remain, and how they can be resolved. (i.e. i wonder if `foldAggregateConstructionIntoAggregateReuse()` might go away) This is a reland of the original commit fcb51d8c2460faa23b71e06abb7e826243887dd6, because originally i forgot to ensure that the base aggregate types match. Reviewed By: spatel Differential Revision: https://reviews.llvm.org/D86530
535 lines
19 KiB
LLVM
535 lines
19 KiB
LLVM
; 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: [[AGG_LEFT_PN1:%.*]] = phi { i32, i32 } [ [[AGG_LEFT]], [[LEFT]] ], [ [[AGG_RIGHT]], [[RIGHT]] ]
|
|
; CHECK-NEXT: [[I6:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT_PN1]], 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:
|
|
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: [[AGG_00_PN1:%.*]] = 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: [[AGG_00_PN1_PN:%.*]] = phi { i32, i32 } [ [[AGG_00_PN1]], [[BB0_MERGE]] ], [ [[AGG_10]], [[BB10]] ]
|
|
; CHECK-NEXT: [[I9:%.*]] = extractvalue { i32, i32 } [[AGG_00_PN1_PN]], 1
|
|
; CHECK-NEXT: [[I8:%.*]] = extractvalue { i32, i32 } [[AGG_00_PN_PN]], 0
|
|
; CHECK-NEXT: call void @baz()
|
|
; CHECK-NEXT: [[I10:%.*]] = insertvalue { i32, i32 } undef, i32 [[I8]], 0
|
|
; CHECK-NEXT: [[I11:%.*]] = insertvalue { i32, i32 } [[I10]], i32 [[I9]], 1
|
|
; CHECK-NEXT: ret { i32, i32 } [[I11]]
|
|
;
|
|
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]] ], [ [[I8:%.*]], [[MIDDLE]] ]
|
|
; CHECK-NEXT: [[AGG_LEFT_PN1:%.*]] = phi { i32, i32 } [ [[AGG_LEFT]], [[LEFT]] ], [ [[AGG_RIGHT]], [[RIGHT]] ], [ [[I8]], [[MIDDLE]] ]
|
|
; CHECK-NEXT: [[I6:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT_PN1]], 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: [[C1:%.*]] = call i1 @geni1()
|
|
; CHECK-NEXT: br i1 [[C1]], label [[END:%.*]], label [[MIDDLE]]
|
|
; CHECK: end:
|
|
; 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 ], [ %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: [[AGG_LEFT_PN1:%.*]] = 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: [[I6:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT_PN1]], 1
|
|
; CHECK-NEXT: [[I5:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT_PN]], 0
|
|
; CHECK-NEXT: call void @quux()
|
|
; 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 %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: [[I8_MERGED:%.*]] = phi { i32, i32 } [ [[AGG_RIGHT:%.*]], [[RIGHT]] ], [ [[AGG_RIGHT]], [[RIGHT]] ], [ [[AGG_LEFT:%.*]], [[LEFT]] ], [ [[AGG_LEFT]], [[LEFT]] ]
|
|
; CHECK-NEXT: call void @baz()
|
|
; CHECK-NEXT: ret { i32, i32 } [[I8_MERGED]]
|
|
;
|
|
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: [[AGG_LEFT_PN1:%.*]] = phi { i32, i32 } [ [[AGG_LEFT]], [[LEFT]] ], [ [[AGG_RIGHT]], [[RIGHT]] ]
|
|
; CHECK-NEXT: [[I7:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT_PN1]], 1
|
|
; CHECK-NEXT: [[I0_PN:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT_PN]], 0
|
|
; CHECK-NEXT: [[I6:%.*]] = insertvalue { i32, i32 } undef, i32 [[I0_PN]], 0
|
|
; 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
|
|
}
|