llvm-project/llvm/test/Transforms/InstCombine/phi-of-insertvalues.ll

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

359 lines
12 KiB
LLVM
Raw Normal View History

; 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: br label [[END:%.*]]
; CHECK: right:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
[InstCombine] PHI-of-insertvalues -> insertvalue-of-PHI's As per statistic, this happens pretty exceedingly rare, but i have seen it in exactly the situations the Phi-aware aggregate reconstruction would have handled, eventually, and allowed invoke -> call fold later on. So while this might be something that other fold will have to learn about, i believe we should be doing this transform in general. Here, we are okay with adding two PHI's to get both the base aggregate, and the inserted value. I'm not sure it makes much sense to restrict it to a single phi (to just the inserted value?), because originally we'd be receiving the final aggregate already.. llvm test-suite + RawSpeed: ``` | statistic name | baseline | proposed | Δ | % | \|%\| | |--------------------------------------------|-----------|-----------|-----:|-------:|------:| | instcombine.NumPHIsOfInsertValues | 0 | 12 | 12 | 0.00% | 0.00% | | asm-printer.EmittedInsts | 8926643 | 8926595 | -48 | 0.00% | 0.00% | | instcombine.NumCombined | 3846614 | 3846640 | 26 | 0.00% | 0.00% | | instcombine.NumConstProp | 24302 | 24293 | -9 | -0.04% | 0.04% | | instcombine.NumDeadInst | 1620140 | 1620112 | -28 | 0.00% | 0.00% | | instcount.NumBrInst | 898466 | 898464 | -2 | 0.00% | 0.00% | | instcount.NumCallInst | 1760819 | 1760875 | 56 | 0.00% | 0.00% | | instcount.NumExtractValueInst | 45659 | 45649 | -10 | -0.02% | 0.02% | | instcount.NumInsertValueInst | 4991 | 4981 | -10 | -0.20% | 0.20% | | instcount.NumIntToPtrInst | 27084 | 27087 | 3 | 0.01% | 0.01% | | instcount.NumPHIInst | 371435 | 371429 | -6 | 0.00% | 0.00% | | instcount.NumStoreInst | 906011 | 906019 | 8 | 0.00% | 0.00% | | instcount.TotalBlocks | 1105520 | 1105518 | -2 | 0.00% | 0.00% | | instcount.TotalInsts | 9795737 | 9795776 | 39 | 0.00% | 0.00% | | simplifycfg.NumInvokes | 2784 | 2786 | 2 | 0.07% | 0.07% | | simplifycfg.NumSimpl | 1001840 | 1001850 | 10 | 0.00% | 0.00% | | simplifycfg.NumSinkCommonInstrs | 15174 | 15170 | -4 | -0.03% | 0.03% | ``` Reviewed By: spatel Differential Revision: https://reviews.llvm.org/D86306
2020-08-25 15:25:34 +08:00
; CHECK-NEXT: [[VAL_LEFT_PN:%.*]] = phi i32 [ [[VAL_LEFT:%.*]], [[LEFT]] ], [ [[VAL_RIGHT:%.*]], [[RIGHT]] ]
; CHECK-NEXT: [[R:%.*]] = insertvalue { i32, i32 } [[AGG:%.*]], i32 [[VAL_LEFT_PN]], 0
; 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: br label [[END:%.*]]
; CHECK: right:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
[InstCombine] PHI-of-insertvalues -> insertvalue-of-PHI's As per statistic, this happens pretty exceedingly rare, but i have seen it in exactly the situations the Phi-aware aggregate reconstruction would have handled, eventually, and allowed invoke -> call fold later on. So while this might be something that other fold will have to learn about, i believe we should be doing this transform in general. Here, we are okay with adding two PHI's to get both the base aggregate, and the inserted value. I'm not sure it makes much sense to restrict it to a single phi (to just the inserted value?), because originally we'd be receiving the final aggregate already.. llvm test-suite + RawSpeed: ``` | statistic name | baseline | proposed | Δ | % | \|%\| | |--------------------------------------------|-----------|-----------|-----:|-------:|------:| | instcombine.NumPHIsOfInsertValues | 0 | 12 | 12 | 0.00% | 0.00% | | asm-printer.EmittedInsts | 8926643 | 8926595 | -48 | 0.00% | 0.00% | | instcombine.NumCombined | 3846614 | 3846640 | 26 | 0.00% | 0.00% | | instcombine.NumConstProp | 24302 | 24293 | -9 | -0.04% | 0.04% | | instcombine.NumDeadInst | 1620140 | 1620112 | -28 | 0.00% | 0.00% | | instcount.NumBrInst | 898466 | 898464 | -2 | 0.00% | 0.00% | | instcount.NumCallInst | 1760819 | 1760875 | 56 | 0.00% | 0.00% | | instcount.NumExtractValueInst | 45659 | 45649 | -10 | -0.02% | 0.02% | | instcount.NumInsertValueInst | 4991 | 4981 | -10 | -0.20% | 0.20% | | instcount.NumIntToPtrInst | 27084 | 27087 | 3 | 0.01% | 0.01% | | instcount.NumPHIInst | 371435 | 371429 | -6 | 0.00% | 0.00% | | instcount.NumStoreInst | 906011 | 906019 | 8 | 0.00% | 0.00% | | instcount.TotalBlocks | 1105520 | 1105518 | -2 | 0.00% | 0.00% | | instcount.TotalInsts | 9795737 | 9795776 | 39 | 0.00% | 0.00% | | simplifycfg.NumInvokes | 2784 | 2786 | 2 | 0.07% | 0.07% | | simplifycfg.NumSimpl | 1001840 | 1001850 | 10 | 0.00% | 0.00% | | simplifycfg.NumSinkCommonInstrs | 15174 | 15170 | -4 | -0.03% | 0.03% | ``` Reviewed By: spatel Differential Revision: https://reviews.llvm.org/D86306
2020-08-25 15:25:34 +08:00
; CHECK-NEXT: [[AGG_LEFT_PN:%.*]] = phi { i32, i32 } [ [[AGG_LEFT:%.*]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ]
; CHECK-NEXT: [[R:%.*]] = insertvalue { i32, i32 } [[AGG_LEFT_PN]], i32 [[VAL:%.*]], 0
; 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: br label [[END:%.*]]
; CHECK: right:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
[InstCombine] PHI-of-insertvalues -> insertvalue-of-PHI's As per statistic, this happens pretty exceedingly rare, but i have seen it in exactly the situations the Phi-aware aggregate reconstruction would have handled, eventually, and allowed invoke -> call fold later on. So while this might be something that other fold will have to learn about, i believe we should be doing this transform in general. Here, we are okay with adding two PHI's to get both the base aggregate, and the inserted value. I'm not sure it makes much sense to restrict it to a single phi (to just the inserted value?), because originally we'd be receiving the final aggregate already.. llvm test-suite + RawSpeed: ``` | statistic name | baseline | proposed | Δ | % | \|%\| | |--------------------------------------------|-----------|-----------|-----:|-------:|------:| | instcombine.NumPHIsOfInsertValues | 0 | 12 | 12 | 0.00% | 0.00% | | asm-printer.EmittedInsts | 8926643 | 8926595 | -48 | 0.00% | 0.00% | | instcombine.NumCombined | 3846614 | 3846640 | 26 | 0.00% | 0.00% | | instcombine.NumConstProp | 24302 | 24293 | -9 | -0.04% | 0.04% | | instcombine.NumDeadInst | 1620140 | 1620112 | -28 | 0.00% | 0.00% | | instcount.NumBrInst | 898466 | 898464 | -2 | 0.00% | 0.00% | | instcount.NumCallInst | 1760819 | 1760875 | 56 | 0.00% | 0.00% | | instcount.NumExtractValueInst | 45659 | 45649 | -10 | -0.02% | 0.02% | | instcount.NumInsertValueInst | 4991 | 4981 | -10 | -0.20% | 0.20% | | instcount.NumIntToPtrInst | 27084 | 27087 | 3 | 0.01% | 0.01% | | instcount.NumPHIInst | 371435 | 371429 | -6 | 0.00% | 0.00% | | instcount.NumStoreInst | 906011 | 906019 | 8 | 0.00% | 0.00% | | instcount.TotalBlocks | 1105520 | 1105518 | -2 | 0.00% | 0.00% | | instcount.TotalInsts | 9795737 | 9795776 | 39 | 0.00% | 0.00% | | simplifycfg.NumInvokes | 2784 | 2786 | 2 | 0.07% | 0.07% | | simplifycfg.NumSimpl | 1001840 | 1001850 | 10 | 0.00% | 0.00% | | simplifycfg.NumSinkCommonInstrs | 15174 | 15170 | -4 | -0.03% | 0.03% | ``` Reviewed By: spatel Differential Revision: https://reviews.llvm.org/D86306
2020-08-25 15:25:34 +08:00
; CHECK-NEXT: [[AGG_LEFT_PN:%.*]] = phi { i32, i32 } [ [[AGG_LEFT:%.*]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ]
; CHECK-NEXT: [[VAL_LEFT_PN:%.*]] = phi i32 [ [[VAL_LEFT:%.*]], [[LEFT]] ], [ [[VAL_RIGHT:%.*]], [[RIGHT]] ]
; CHECK-NEXT: [[R:%.*]] = insertvalue { i32, i32 } [[AGG_LEFT_PN]], i32 [[VAL_LEFT_PN]], 0
; 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
}
; More complex aggregates are fine, too, as long as indicies match.
define {{ i32, i32 }, { i32, i32 }} @test7({{ i32, i32 }, { i32, i32 }} %agg, i32 %val_left, i32 %val_right, i1 %c) {
; CHECK-LABEL: @test7(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
; CHECK: left:
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: right:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
[InstCombine] PHI-of-insertvalues -> insertvalue-of-PHI's As per statistic, this happens pretty exceedingly rare, but i have seen it in exactly the situations the Phi-aware aggregate reconstruction would have handled, eventually, and allowed invoke -> call fold later on. So while this might be something that other fold will have to learn about, i believe we should be doing this transform in general. Here, we are okay with adding two PHI's to get both the base aggregate, and the inserted value. I'm not sure it makes much sense to restrict it to a single phi (to just the inserted value?), because originally we'd be receiving the final aggregate already.. llvm test-suite + RawSpeed: ``` | statistic name | baseline | proposed | Δ | % | \|%\| | |--------------------------------------------|-----------|-----------|-----:|-------:|------:| | instcombine.NumPHIsOfInsertValues | 0 | 12 | 12 | 0.00% | 0.00% | | asm-printer.EmittedInsts | 8926643 | 8926595 | -48 | 0.00% | 0.00% | | instcombine.NumCombined | 3846614 | 3846640 | 26 | 0.00% | 0.00% | | instcombine.NumConstProp | 24302 | 24293 | -9 | -0.04% | 0.04% | | instcombine.NumDeadInst | 1620140 | 1620112 | -28 | 0.00% | 0.00% | | instcount.NumBrInst | 898466 | 898464 | -2 | 0.00% | 0.00% | | instcount.NumCallInst | 1760819 | 1760875 | 56 | 0.00% | 0.00% | | instcount.NumExtractValueInst | 45659 | 45649 | -10 | -0.02% | 0.02% | | instcount.NumInsertValueInst | 4991 | 4981 | -10 | -0.20% | 0.20% | | instcount.NumIntToPtrInst | 27084 | 27087 | 3 | 0.01% | 0.01% | | instcount.NumPHIInst | 371435 | 371429 | -6 | 0.00% | 0.00% | | instcount.NumStoreInst | 906011 | 906019 | 8 | 0.00% | 0.00% | | instcount.TotalBlocks | 1105520 | 1105518 | -2 | 0.00% | 0.00% | | instcount.TotalInsts | 9795737 | 9795776 | 39 | 0.00% | 0.00% | | simplifycfg.NumInvokes | 2784 | 2786 | 2 | 0.07% | 0.07% | | simplifycfg.NumSimpl | 1001840 | 1001850 | 10 | 0.00% | 0.00% | | simplifycfg.NumSinkCommonInstrs | 15174 | 15170 | -4 | -0.03% | 0.03% | ``` Reviewed By: spatel Differential Revision: https://reviews.llvm.org/D86306
2020-08-25 15:25:34 +08:00
; CHECK-NEXT: [[VAL_LEFT_PN:%.*]] = phi i32 [ [[VAL_LEFT:%.*]], [[LEFT]] ], [ [[VAL_RIGHT:%.*]], [[RIGHT]] ]
; CHECK-NEXT: [[R:%.*]] = insertvalue { { i32, i32 }, { i32, i32 } } [[AGG:%.*]], i32 [[VAL_LEFT_PN]], 0, 0
; CHECK-NEXT: ret { { i32, i32 }, { i32, i32 } } [[R]]
;
entry:
br i1 %c, label %left, label %right
left:
%i0 = insertvalue {{ i32, i32 }, { i32, i32 }} %agg, i32 %val_left, 0, 0
br label %end
right:
%i1 = insertvalue {{ i32, i32 }, { i32, i32 }} %agg, i32 %val_right, 0, 0
br label %end
end:
%r = phi {{ i32, i32 }, { i32, i32 }} [ %i0, %left ], [ %i1, %right ]
ret {{ i32, i32 }, { i32, i32 }} %r
}
; The indicies must fully match, on all levels.
define {{ i32, i32 }, { i32, i32 }} @test8({{ i32, i32 }, { i32, i32 }} %agg, i32 %val_left, i32 %val_right, i1 %c) {
; CHECK-LABEL: @test8(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
; CHECK: left:
; CHECK-NEXT: [[I0:%.*]] = insertvalue { { i32, i32 }, { i32, i32 } } [[AGG:%.*]], i32 [[VAL_LEFT:%.*]], 0, 0
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: right:
; CHECK-NEXT: [[I1:%.*]] = insertvalue { { i32, i32 }, { i32, i32 } } [[AGG]], i32 [[VAL_RIGHT:%.*]], 0, 1
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[R:%.*]] = phi { { i32, i32 }, { i32, i32 } } [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]
; CHECK-NEXT: ret { { i32, i32 }, { i32, i32 } } [[R]]
;
entry:
br i1 %c, label %left, label %right
left:
%i0 = insertvalue {{ i32, i32 }, { i32, i32 }} %agg, i32 %val_left, 0, 0
br label %end
right:
%i1 = insertvalue {{ i32, i32 }, { i32, i32 }} %agg, i32 %val_right, 0, 1
br label %end
end:
%r = phi {{ i32, i32 }, { i32, i32 }} [ %i0, %left ], [ %i1, %right ]
ret {{ i32, i32 }, { i32, i32 }} %r
}
; It is fine if there are multiple uses of the PHI's value, as long as they are all in the PHI node itself
define { i32, i32 } @test9({ i32, i32 } %agg, i32 %val_left, i32 %val_right, i1 %c0, i1 %c1) {
; CHECK-LABEL: @test9(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[I0:%.*]] = insertvalue { i32, i32 } [[AGG:%.*]], i32 [[VAL_LEFT:%.*]], 0
; CHECK-NEXT: [[I1:%.*]] = insertvalue { i32, i32 } [[AGG]], i32 [[VAL_RIGHT:%.*]], 0
; CHECK-NEXT: br i1 [[C0:%.*]], label [[END:%.*]], label [[DISPATCH:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: br i1 [[C1:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
; CHECK: left:
; CHECK-NEXT: br label [[END]]
; CHECK: right:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[R:%.*]] = phi { i32, i32 } [ [[I0]], [[ENTRY:%.*]] ], [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]
; CHECK-NEXT: ret { i32, i32 } [[R]]
;
entry:
%i0 = insertvalue { i32, i32 } %agg, i32 %val_left, 0
%i1 = insertvalue { i32, i32 } %agg, i32 %val_right, 0
br i1 %c0, label %end, label %dispatch
dispatch:
br i1 %c1, label %left, label %right
left:
br label %end
right:
br label %end
end:
%r = phi { i32, i32 } [ %i0, %entry ], [ %i0, %left ], [ %i1, %right ]
ret { i32, i32 } %r
}
; Which isn't the case here, there is a legitimate external use.
define { i32, i32 } @test10({ i32, i32 } %agg, i32 %val_left, i32 %val_right, i1 %c0, i1 %c1) {
; CHECK-LABEL: @test10(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[I0:%.*]] = insertvalue { i32, i32 } [[AGG:%.*]], i32 [[VAL_LEFT:%.*]], 0
; CHECK-NEXT: [[I1:%.*]] = insertvalue { i32, i32 } [[AGG]], i32 [[VAL_RIGHT:%.*]], 0
; CHECK-NEXT: call void @usei32i32agg({ i32, i32 } [[I0]])
; CHECK-NEXT: br i1 [[C0:%.*]], label [[END:%.*]], label [[DISPATCH:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: br i1 [[C1:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
; CHECK: left:
; CHECK-NEXT: br label [[END]]
; CHECK: right:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[R:%.*]] = phi { i32, i32 } [ [[I0]], [[ENTRY:%.*]] ], [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]
; CHECK-NEXT: ret { i32, i32 } [[R]]
;
entry:
%i0 = insertvalue { i32, i32 } %agg, i32 %val_left, 0
%i1 = insertvalue { i32, i32 } %agg, i32 %val_right, 0
call void @usei32i32agg({ i32, i32 } %i0)
br i1 %c0, label %end, label %dispatch
dispatch:
br i1 %c1, label %left, label %right
left:
br label %end
right:
br label %end
end:
%r = phi { i32, i32 } [ %i0, %entry ], [ %i0, %left ], [ %i1, %right ]
ret { i32, i32 } %r
}