llvm/llvm/test/Transforms/InstCombine/phi-aware-aggregate-reconstruction.ll

; 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
}