; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes=instcombine -S < %s | FileCheck %s

define i32 @phi_freeze_same_consts(i1 %c0, i1 %c1) {
; CHECK-LABEL: define i32 @phi_freeze_same_consts(
; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    br i1 [[C0]], label %[[BB_FREEZE:.*]], label %[[BB_OTHER:.*]]
; CHECK:       [[BB_FREEZE]]:
; CHECK-NEXT:    br label %[[FINAL:.*]]
; CHECK:       [[BB_OTHER]]:
; CHECK-NEXT:    br i1 [[C1]], label %[[CA:.*]], label %[[CB:.*]]
; CHECK:       [[CA]]:
; CHECK-NEXT:    br label %[[FINAL]]
; CHECK:       [[CB]]:
; CHECK-NEXT:    br label %[[FINAL]]
; CHECK:       [[FINAL]]:
; CHECK-NEXT:    ret i32 42
;
entry:
  br i1 %c0, label %bb_freeze, label %bb_other

bb_freeze:
  %f = freeze i32 undef
  br label %final

bb_other:
  br i1 %c1, label %cA, label %cB
cA:
  br label %final
cB:
  br label %final

final:
  %phi = phi i32 [ %f, %bb_freeze ], [ 42, %cA ], [ 42, %cB ]
  ret i32 %phi
}

define i32 @phi_freeze_mixed_consts(i1 %c0, i1 %c1) {
; CHECK-LABEL: define i32 @phi_freeze_mixed_consts(
; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    br i1 [[C0]], label %[[BB_FREEZE:.*]], label %[[BB_OTHER:.*]]
; CHECK:       [[BB_FREEZE]]:
; CHECK-NEXT:    br label %[[FINAL:.*]]
; CHECK:       [[BB_OTHER]]:
; CHECK-NEXT:    br i1 [[C1]], label %[[CA:.*]], label %[[CB:.*]]
; CHECK:       [[CA]]:
; CHECK-NEXT:    br label %[[FINAL]]
; CHECK:       [[CB]]:
; CHECK-NEXT:    br label %[[FINAL]]
; CHECK:       [[FINAL]]:
; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ 0, %[[BB_FREEZE]] ], [ 42, %[[CA]] ], [ 7, %[[CB]] ]
; CHECK-NEXT:    ret i32 [[PHI]]
;
entry:
  br i1 %c0, label %bb_freeze, label %bb_other

bb_freeze:
  %f = freeze i32 undef
  br label %final

bb_other:
  br i1 %c1, label %cA, label %cB
cA:
  br label %final
cB:
  br label %final

final:
  %phi = phi i32 [ %f, %bb_freeze ], [ 42, %cA ], [ 7, %cB ]
  ret i32 %phi
}

define i32 @phi_freeze_with_nonconst_incoming(i32 %x, i1 %c0, i1 %c1) {
; CHECK-LABEL: define i32 @phi_freeze_with_nonconst_incoming(
; CHECK-SAME: i32 [[X:%.*]], i1 [[C0:%.*]], i1 [[C1:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    br i1 [[C0]], label %[[BB_FREEZE:.*]], label %[[BB_OTHER:.*]]
; CHECK:       [[BB_FREEZE]]:
; CHECK-NEXT:    br label %[[FINAL:.*]]
; CHECK:       [[BB_OTHER]]:
; CHECK-NEXT:    br i1 [[C1]], label %[[CA:.*]], label %[[CB:.*]]
; CHECK:       [[CA]]:
; CHECK-NEXT:    br label %[[FINAL]]
; CHECK:       [[CB]]:
; CHECK-NEXT:    br label %[[FINAL]]
; CHECK:       [[FINAL]]:
; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ 0, %[[BB_FREEZE]] ], [ [[X]], %[[CA]] ], [ 13, %[[CB]] ]
; CHECK-NEXT:    ret i32 [[PHI]]
;
entry:
  br i1 %c0, label %bb_freeze, label %bb_other

bb_freeze:
  %f = freeze i32 undef
  br label %final

bb_other:
  br i1 %c1, label %cA, label %cB
cA:
  br label %final
cB:
  br label %final

final:
  %phi = phi i32 [ %f, %bb_freeze ], [ %x, %cA ], [ 13, %cB ]
  ret i32 %phi
}

define <4 x i8> @phi_freeze_vector(i1 %c0, i1 %c1) {
; CHECK-LABEL: define <4 x i8> @phi_freeze_vector(
; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    br i1 [[C0]], label %[[BB_FREEZE:.*]], label %[[BB_OTHER:.*]]
; CHECK:       [[BB_FREEZE]]:
; CHECK-NEXT:    br label %[[FINAL:.*]]
; CHECK:       [[BB_OTHER]]:
; CHECK-NEXT:    br i1 [[C1]], label %[[CA:.*]], label %[[CB:.*]]
; CHECK:       [[CA]]:
; CHECK-NEXT:    br label %[[FINAL]]
; CHECK:       [[CB]]:
; CHECK-NEXT:    br label %[[FINAL]]
; CHECK:       [[FINAL]]:
; CHECK-NEXT:    ret <4 x i8> splat (i8 9)
;
entry:
  br i1 %c0, label %bb_freeze, label %bb_other

bb_freeze:
  %f = freeze <4 x i8> undef
  br label %final

bb_other:
  br i1 %c1, label %cA, label %cB

cA:
  br label %final

cB:
  br label %final

final:
  %phi = phi <4 x i8> [ %f, %bb_freeze ],
  [<i8 9, i8 9, i8 9, i8 9>, %cA ],
  [<i8 9, i8 9, i8 9, i8 9>, %cB ]
  ret <4 x i8> %phi
}

define i32 @multi_use_one_folds_one_not_zero(i1 %c0, i1 %c1, i1 %c2) {
; CHECK-LABEL: define i32 @multi_use_one_folds_one_not_zero(
; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    br i1 [[C0]], label %[[BB_OTHER3:.*]], label %[[CC1:.*]]
; CHECK:       [[BB_OTHER3]]:
; CHECK-NEXT:    br label %[[MID:.*]]
; CHECK:       [[CC1]]:
; CHECK-NEXT:    br i1 [[C1]], label %[[CA:.*]], label %[[CB:.*]]
; CHECK:       [[CA]]:
; CHECK-NEXT:    br label %[[MID]]
; CHECK:       [[CB]]:
; CHECK-NEXT:    br label %[[MID]]
; CHECK:       [[MID]]:
; CHECK-NEXT:    [[PHI_FOLD:%.*]] = phi i32 [ 0, %[[BB_OTHER3]] ], [ 1, %[[CA]] ], [ 1, %[[CB]] ]
; CHECK-NEXT:    br i1 [[C2]], label %[[BB_FREEZE2:.*]], label %[[CD:.*]]
; CHECK:       [[BB_FREEZE2]]:
; CHECK-NEXT:    br label %[[FINAL:.*]]
; CHECK:       [[BB_OTHER2:.*:]]
; CHECK-NEXT:    br i1 true, label %[[CA]], label %[[CB]]
; CHECK:       [[CC:.*:]]
; CHECK-NEXT:    br label %[[FINAL]]
; CHECK:       [[CD]]:
; CHECK-NEXT:    br label %[[FINAL]]
; CHECK:       [[FINAL]]:
; CHECK-NEXT:    ret i32 [[PHI_FOLD]]
;
entry:
  %f = freeze i32 undef
  br i1 %c0, label %bb_freeze, label %bb_other
bb_freeze:
  br label %mid
bb_other:
  br i1 %c1, label %cA, label %cB
cA:
  br label %mid
cB:
  br label %mid
mid:
  %phi_no_fold  = phi i32 [ %f, %bb_freeze ], [ 1, %cA ], [ 1, %cB ]
  br i1 %c2, label %bb_freeze2, label %cD
bb_freeze2:
  br label %final
bb_other2:
  br i1 %c1, label %cA, label %cB
cC:
  br label %final
cD:
  br label %final
final:
  %phi_fold  = phi i32 [ %f, %bb_freeze2 ], [ 0, %cC ], [ 0, %cD ]
  %a = add i32 %phi_fold, %phi_no_fold
  ret i32 %a
}

define i32 @phi_freeze_poison(i1 %c0, i1 %c1) {
; CHECK-LABEL: define i32 @phi_freeze_poison(
; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    br i1 [[C0]], label %[[BB_FREEZE:.*]], label %[[BB_OTHER:.*]]
; CHECK:       [[BB_FREEZE]]:
; CHECK-NEXT:    br label %[[FINAL:.*]]
; CHECK:       [[BB_OTHER]]:
; CHECK-NEXT:    br i1 [[C1]], label %[[CA:.*]], label %[[CB:.*]]
; CHECK:       [[CA]]:
; CHECK-NEXT:    br label %[[FINAL]]
; CHECK:       [[CB]]:
; CHECK-NEXT:    br label %[[FINAL]]
; CHECK:       [[FINAL]]:
; CHECK-NEXT:    ret i32 0
;
entry:
  br i1 %c0, label %bb_freeze, label %bb_other

bb_freeze:
  %f = freeze i32 undef
  br label %final

bb_other:
  br i1 %c1, label %cA, label %cB
cA:
  br label %final
cB:
  br label %final

final:
  %phi = phi i32 [ %f, %bb_freeze ], [ poison, %cA ], [ poison, %cB ]
  ret i32 %phi
}

define <2 x i32> @phi_freeze_poison_vec(i1 %c0, i1 %c1) {
; CHECK-LABEL: define <2 x i32> @phi_freeze_poison_vec(
; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    br i1 [[C0]], label %[[BB_FREEZE:.*]], label %[[BB_OTHER:.*]]
; CHECK:       [[BB_FREEZE]]:
; CHECK-NEXT:    br label %[[FINAL:.*]]
; CHECK:       [[BB_OTHER]]:
; CHECK-NEXT:    br i1 [[C1]], label %[[CA:.*]], label %[[CB:.*]]
; CHECK:       [[CA]]:
; CHECK-NEXT:    br label %[[FINAL]]
; CHECK:       [[CB]]:
; CHECK-NEXT:    br label %[[FINAL]]
; CHECK:       [[FINAL]]:
; CHECK-NEXT:    [[PHI:%.*]] = phi <2 x i32> [ zeroinitializer, %[[BB_FREEZE]] ], [ <i32 poison, i32 1>, %[[CA]] ], [ <i32 poison, i32 1>, %[[CB]] ]
; CHECK-NEXT:    ret <2 x i32> [[PHI]]
;
entry:
  br i1 %c0, label %bb_freeze, label %bb_other

bb_freeze:
  %f = freeze <2 x i32> undef
  br label %final

bb_other:
  br i1 %c1, label %cA, label %cB
cA:
  br label %final
cB:
  br label %final

final:
  %phi = phi <2 x i32> [ %f, %bb_freeze ], [ <i32 poison, i32 1>, %cA ], [ <i32 poison, i32 1>, %cB ]
  ret <2 x i32> %phi
}
