llvm/llvm/test/Transforms/SROA/phi-gep.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes='sroa<preserve-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-PRESERVE-CFG
; RUN: opt -S -passes='sroa<modify-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-MODIFY-CFG

%pair = type { i32, i32 }

define i32 @test_sroa_phi_gep(i1 %cond) {
; CHECK-LABEL: @test_sroa_phi_gep(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[END:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    br label [[END]]
; CHECK:       end:
; CHECK-NEXT:    [[PHI_SROA_PHI_SROA_SPECULATED:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ 2, [[IF_THEN]] ]
; CHECK-NEXT:    ret i32 [[PHI_SROA_PHI_SROA_SPECULATED]]
;
entry:
  %a = alloca %pair, align 4
  %b = alloca %pair, align 4
  %gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
  %gep_b = getelementptr inbounds %pair, ptr %b, i32 0, i32 1
  store i32 1, ptr %gep_a, align 4
  store i32 2, ptr %gep_b, align 4
  br i1 %cond, label %if.then, label %end

if.then:
  br label %end

end:
  %phi = phi ptr [ %a, %entry], [ %b, %if.then ]
  %gep = getelementptr inbounds %pair, ptr %phi, i32 0, i32 1
  %load = load i32, ptr %gep, align 4
  ret i32 %load
}

define i32 @test_sroa_phi_gep_non_inbound(i1 %cond) {
; CHECK-LABEL: @test_sroa_phi_gep_non_inbound(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[END:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    br label [[END]]
; CHECK:       end:
; CHECK-NEXT:    [[PHI_SROA_PHI_SROA_SPECULATED:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ 2, [[IF_THEN]] ]
; CHECK-NEXT:    ret i32 [[PHI_SROA_PHI_SROA_SPECULATED]]
;
entry:
  %a = alloca %pair, align 4
  %b = alloca %pair, align 4
  %gep_a = getelementptr %pair, ptr %a, i32 0, i32 1
  %gep_b = getelementptr %pair, ptr %b, i32 0, i32 1
  store i32 1, ptr %gep_a, align 4
  store i32 2, ptr %gep_b, align 4
  br i1 %cond, label %if.then, label %end

if.then:
  br label %end

end:
  %phi = phi ptr [ %a, %entry], [ %b, %if.then ]
  %gep = getelementptr %pair, ptr %phi, i32 0, i32 1
  %load = load i32, ptr %gep, align 4
  ret i32 %load
}

define i32 @test_sroa_phi_gep_poison(i1 %cond) {
; CHECK-LABEL: @test_sroa_phi_gep_poison(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[END:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[PHI_SROA_PHI_SROA_SPECULATE_LOAD_IF_THEN:%.*]] = load i32, ptr poison, align 4
; CHECK-NEXT:    br label [[END]]
; CHECK:       end:
; CHECK-NEXT:    [[PHI_SROA_PHI_SROA_SPECULATED:%.*]] = phi i32 [ undef, [[ENTRY:%.*]] ], [ [[PHI_SROA_PHI_SROA_SPECULATE_LOAD_IF_THEN]], [[IF_THEN]] ]
; CHECK-NEXT:    ret i32 [[PHI_SROA_PHI_SROA_SPECULATED]]
;
entry:
  %a = alloca %pair, align 4
  br i1 %cond, label %if.then, label %end

if.then:
  br label %end

end:
  %phi = phi ptr [ %a, %entry], [ poison, %if.then ]
  %gep = getelementptr inbounds %pair, ptr %phi, i32 0, i32 1
  %load = load i32, ptr %gep, align 4
  ret i32 %load
}

@g = global %pair zeroinitializer, align 4

define i32 @test_sroa_phi_gep_global(i1 %cond) {
; CHECK-LABEL: @test_sroa_phi_gep_global(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[END:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[PHI_SROA_PHI_SROA_SPECULATE_LOAD_IF_THEN:%.*]] = load i32, ptr getelementptr inbounds ([[PAIR:%.*]], ptr @g, i32 0, i32 1), align 4
; CHECK-NEXT:    br label [[END]]
; CHECK:       end:
; CHECK-NEXT:    [[PHI_SROA_PHI_SROA_SPECULATED:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[PHI_SROA_PHI_SROA_SPECULATE_LOAD_IF_THEN]], [[IF_THEN]] ]
; CHECK-NEXT:    ret i32 [[PHI_SROA_PHI_SROA_SPECULATED]]
;
entry:
  %a = alloca %pair, align 4
  %gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
  store i32 1, ptr %gep_a, align 4
  br i1 %cond, label %if.then, label %end

if.then:
  br label %end

end:
  %phi = phi ptr [ %a, %entry], [ @g, %if.then ]
  %gep = getelementptr inbounds %pair, ptr %phi, i32 0, i32 1
  %load = load i32, ptr %gep, align 4
  ret i32 %load
}

define i32 @test_sroa_phi_gep_arg_phi_inspt(i1 %cond) {
; CHECK-LABEL: @test_sroa_phi_gep_arg_phi_inspt(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[FOR:%.*]], label [[END:%.*]]
; CHECK:       for:
; CHECK-NEXT:    [[PHI_INSPT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I:%.*]], [[FOR]] ]
; CHECK-NEXT:    [[I]] = add i32 [[PHI_INSPT]], 1
; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ult i32 [[I]], 10
; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[FOR]], label [[END]]
; CHECK:       end:
; CHECK-NEXT:    [[PHI_SROA_PHI_SROA_SPECULATED:%.*]] = phi i32 [ 1, [[ENTRY]] ], [ 2, [[FOR]] ]
; CHECK-NEXT:    ret i32 [[PHI_SROA_PHI_SROA_SPECULATED]]
;
entry:
  %a = alloca %pair, align 4
  %b = alloca %pair, align 4
  %gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
  %gep_b = getelementptr inbounds %pair, ptr %b, i32 0, i32 1
  store i32 1, ptr %gep_a, align 4
  store i32 2, ptr %gep_b, align 4
  br i1 %cond, label %for, label %end

for:
  %phi_inspt = phi i32 [ 0, %entry ], [ %i, %for ]
  %i = add i32 %phi_inspt, 1
  %loop.cond = icmp ult i32 %i, 10
  br i1 %loop.cond, label %for, label %end

end:
  %phi = phi ptr [ %a, %entry], [ %b, %for ]
  %gep = getelementptr inbounds %pair, ptr %phi, i32 0, i32 1
  %load = load i32, ptr %gep, align 4
  ret i32 %load
}

define i32 @test_sroa_phi_gep_phi_inspt(i1 %cond) {
; CHECK-LABEL: @test_sroa_phi_gep_phi_inspt(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[A:%.*]] = alloca [[PAIR:%.*]], align 4
; CHECK-NEXT:    [[B:%.*]] = alloca [[PAIR]], align 4
; CHECK-NEXT:    [[GEP_A:%.*]] = getelementptr inbounds [[PAIR]], ptr [[A]], i32 0, i32 1
; CHECK-NEXT:    [[GEP_B:%.*]] = getelementptr inbounds [[PAIR]], ptr [[B]], i32 0, i32 1
; CHECK-NEXT:    store i32 1, ptr [[GEP_A]], align 4
; CHECK-NEXT:    store i32 2, ptr [[GEP_B]], align 4
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[FOR:%.*]], label [[END:%.*]]
; CHECK:       for:
; CHECK-NEXT:    [[PHI_IN:%.*]] = phi ptr [ null, [[ENTRY:%.*]] ], [ [[B]], [[FOR]] ]
; CHECK-NEXT:    [[PHI_INSPT:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[I:%.*]], [[FOR]] ]
; CHECK-NEXT:    [[I]] = add i32 [[PHI_INSPT]], 1
; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ult i32 [[I]], 10
; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[FOR]], label [[END]]
; CHECK:       end:
; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[PHI_IN]], [[FOR]] ]
; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[PHI]], i32 0, i32 1
; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT:    ret i32 [[LOAD]]
;
entry:
  %a = alloca %pair, align 4
  %b = alloca %pair, align 4
  %gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
  %gep_b = getelementptr inbounds %pair, ptr %b, i32 0, i32 1
  store i32 1, ptr %gep_a, align 4
  store i32 2, ptr %gep_b, align 4
  br i1 %cond, label %for, label %end

for:
  %phi_in = phi ptr [ null, %entry ], [ %b, %for ]
  %phi_inspt = phi i32 [ 0, %entry ], [ %i, %for ]
  %i = add i32 %phi_inspt, 1
  %loop.cond = icmp ult i32 %i, 10
  br i1 %loop.cond, label %for, label %end

end:
  %phi = phi ptr [ %a, %entry], [ %phi_in, %for ]
  %gep = getelementptr inbounds %pair, ptr %phi, i32 0, i32 1
  %load = load i32, ptr %gep, align 4
  ret i32 %load
}

define i32 @test_sroa_gep_phi_gep(i1 %cond) {
; CHECK-LABEL: @test_sroa_gep_phi_gep(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[A_SROA_0:%.*]] = alloca i32, align 4
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[FOR:%.*]], label [[END:%.*]]
; CHECK:       for:
; CHECK-NEXT:    [[PHI_I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I:%.*]], [[FOR]] ]
; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[A_SROA_0]], [[ENTRY]] ], [ [[GEP_FOR:%.*]], [[FOR]] ]
; CHECK-NEXT:    [[I]] = add i32 [[PHI_I]], 1
; CHECK-NEXT:    [[GEP_FOR]] = getelementptr inbounds i32, ptr [[PHI]], i32 0
; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ult i32 [[I]], 10
; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[FOR]], label [[END]]
; CHECK:       end:
; CHECK-NEXT:    [[PHI_END:%.*]] = phi ptr [ [[A_SROA_0]], [[ENTRY]] ], [ [[PHI]], [[FOR]] ]
; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[PHI_END]], align 4
; CHECK-NEXT:    ret i32 [[LOAD]]
;
entry:
  %a = alloca %pair, align 4
  %gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
  br i1 %cond, label %for, label %end

for:
  %phi_i = phi i32 [ 0, %entry ], [ %i, %for ]
  %phi = phi ptr [ %gep_a, %entry], [ %gep_for, %for ]
  %i = add i32 %phi_i, 1
  %gep_for = getelementptr inbounds i32, ptr %phi, i32 0
  %loop.cond = icmp ult i32 %i, 10
  br i1 %loop.cond, label %for, label %end

end:
  %phi_end = phi ptr [ %gep_a, %entry], [ %phi, %for ]
  %load = load i32, ptr %phi_end, align 4
  ret i32 %load
}

define i32 @test_sroa_invoke_phi_gep(i1 %cond) personality ptr @__gxx_personality_v0 {
; CHECK-LABEL: @test_sroa_invoke_phi_gep(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[A:%.*]] = alloca [[PAIR:%.*]], align 4
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[CALL:%.*]], label [[END:%.*]]
; CHECK:       call:
; CHECK-NEXT:    [[B:%.*]] = invoke ptr @foo()
; CHECK-NEXT:            to label [[END]] unwind label [[INVOKE_CATCH:%.*]]
; CHECK:       end:
; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[A]], [[ENTRY:%.*]] ], [ [[B]], [[CALL]] ]
; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[PHI]], i32 0, i32 1
; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT:    ret i32 [[LOAD]]
; CHECK:       invoke_catch:
; CHECK-NEXT:    [[RES:%.*]] = landingpad { ptr, i32 }
; CHECK-NEXT:            catch ptr null
; CHECK-NEXT:    ret i32 0
;
entry:
  %a = alloca %pair, align 4
  br i1 %cond, label %call, label %end

call:
  %b = invoke ptr @foo()
  to label %end unwind label %invoke_catch

end:
  %phi = phi ptr [ %a, %entry], [ %b, %call ]
  %gep = getelementptr inbounds %pair, ptr %phi, i32 0, i32 1
  %load = load i32, ptr %gep, align 4
  ret i32 %load

invoke_catch:
  %res = landingpad { ptr, i32 }
  catch ptr null
  ret i32 0
}

define i32 @test_sroa_phi_gep_nonconst_idx(i1 %cond, i32 %idx) {
; CHECK-LABEL: @test_sroa_phi_gep_nonconst_idx(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[A:%.*]] = alloca [[PAIR:%.*]], align 4
; CHECK-NEXT:    [[B:%.*]] = alloca [[PAIR]], align 4
; CHECK-NEXT:    [[GEP_A:%.*]] = getelementptr inbounds [[PAIR]], ptr [[A]], i32 0, i32 1
; CHECK-NEXT:    [[GEP_B:%.*]] = getelementptr inbounds [[PAIR]], ptr [[B]], i32 0, i32 1
; CHECK-NEXT:    store i32 1, ptr [[GEP_A]], align 4
; CHECK-NEXT:    store i32 2, ptr [[GEP_B]], align 4
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[END:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    br label [[END]]
; CHECK:       end:
; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[A]], [[ENTRY:%.*]] ], [ [[B]], [[IF_THEN]] ]
; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[PHI]], i32 [[IDX:%.*]], i32 1
; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT:    ret i32 [[LOAD]]
;
entry:
  %a = alloca %pair, align 4
  %b = alloca %pair, align 4
  %gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
  %gep_b = getelementptr inbounds %pair, ptr %b, i32 0, i32 1
  store i32 1, ptr %gep_a, align 4
  store i32 2, ptr %gep_b, align 4
  br i1 %cond, label %if.then, label %end

if.then:
  br label %end

end:
  %phi = phi ptr [ %a, %entry], [ %b, %if.then ]
  %gep = getelementptr inbounds %pair, ptr %phi, i32 %idx, i32 1
  %load = load i32, ptr %gep, align 4
  ret i32 %load
}

define void @test_sroa_gep_phi_select_other_block(i1 %c1, i1 %c2, ptr %ptr) {
; CHECK-LABEL: @test_sroa_gep_phi_select_other_block(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca [[PAIR:%.*]], align 8
; CHECK-NEXT:    br label [[WHILE_BODY:%.*]]
; CHECK:       while.body:
; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[ALLOCA]], [[ENTRY:%.*]] ], [ [[SELECT:%.*]], [[WHILE_BODY]] ]
; CHECK-NEXT:    [[SELECT]] = select i1 [[C1:%.*]], ptr [[PHI]], ptr [[PTR:%.*]]
; CHECK-NEXT:    br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[WHILE_BODY]]
; CHECK:       exit:
; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[PHI]], i64 1
; CHECK-NEXT:    unreachable
;
entry:
  %alloca = alloca %pair, align 8
  br label %while.body

while.body:
  %phi = phi ptr [ %alloca, %entry ], [ %select, %while.body ]
  %select = select i1 %c1, ptr %phi, ptr %ptr
  br i1 %c2, label %exit, label %while.body

exit:
  %gep = getelementptr inbounds %pair, ptr %phi, i64 1
  unreachable
}

define void @test_sroa_gep_phi_select_same_block(i1 %c1, i1 %c2, ptr %ptr) {
; CHECK-LABEL: @test_sroa_gep_phi_select_same_block(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca [[PAIR:%.*]], align 8
; CHECK-NEXT:    br label [[WHILE_BODY:%.*]]
; CHECK:       while.body:
; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[ALLOCA]], [[ENTRY:%.*]] ], [ [[SELECT:%.*]], [[WHILE_BODY]] ]
; CHECK-NEXT:    [[SELECT]] = select i1 [[C1:%.*]], ptr [[PHI]], ptr [[PTR:%.*]]
; CHECK-NEXT:    [[PHI_SROA_GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[PHI]], i64 1
; CHECK-NEXT:    [[PTR_SROA_GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[PTR]], i64 1
; CHECK-NEXT:    [[SELECT_SROA_SEL:%.*]] = select i1 [[C1]], ptr [[PHI_SROA_GEP]], ptr [[PTR_SROA_GEP]]
; CHECK-NEXT:    br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[WHILE_BODY]]
; CHECK:       exit:
; CHECK-NEXT:    ret void
;
entry:
  %alloca = alloca %pair, align 8
  br label %while.body

while.body:
  %phi = phi ptr [ %alloca, %entry ], [ %select, %while.body ]
  %select = select i1 %c1, ptr %phi, ptr %ptr
  %gep = getelementptr inbounds %pair, ptr %select, i64 1
  br i1 %c2, label %exit, label %while.body

exit:
  ret void
}

define void @test_sroa_gep_phi_select_same_block_nuw(i1 %c1, i1 %c2, ptr %ptr) {
; CHECK-LABEL: @test_sroa_gep_phi_select_same_block_nuw(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca [[PAIR:%.*]], align 8
; CHECK-NEXT:    br label [[WHILE_BODY:%.*]]
; CHECK:       while.body:
; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[ALLOCA]], [[ENTRY:%.*]] ], [ [[SELECT:%.*]], [[WHILE_BODY]] ]
; CHECK-NEXT:    [[SELECT]] = select i1 [[C1:%.*]], ptr [[PHI]], ptr [[PTR:%.*]]
; CHECK-NEXT:    [[PHI_SROA_GEP:%.*]] = getelementptr nuw [[PAIR]], ptr [[PHI]], i64 1
; CHECK-NEXT:    [[PTR_SROA_GEP:%.*]] = getelementptr nuw [[PAIR]], ptr [[PTR]], i64 1
; CHECK-NEXT:    [[SELECT_SROA_SEL:%.*]] = select i1 [[C1]], ptr [[PHI_SROA_GEP]], ptr [[PTR_SROA_GEP]]
; CHECK-NEXT:    br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[WHILE_BODY]]
; CHECK:       exit:
; CHECK-NEXT:    ret void
;
entry:
  %alloca = alloca %pair, align 8
  br label %while.body

while.body:
  %phi = phi ptr [ %alloca, %entry ], [ %select, %while.body ]
  %select = select i1 %c1, ptr %phi, ptr %ptr
  %gep = getelementptr nuw %pair, ptr %select, i64 1
  br i1 %c2, label %exit, label %while.body

exit:
  ret void
}

define i32 @test_sroa_gep_cast_phi_gep(i1 %cond) {
; CHECK-LABEL: @test_sroa_gep_cast_phi_gep(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[A_SROA_0:%.*]] = alloca i32, align 4
; CHECK-NEXT:    store i32 1065353216, ptr [[A_SROA_0]], align 4
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[FOR:%.*]], label [[END:%.*]]
; CHECK:       for:
; CHECK-NEXT:    [[PHI_I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I:%.*]], [[FOR]] ]
; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[A_SROA_0]], [[ENTRY]] ], [ [[GEP_FOR:%.*]], [[FOR]] ]
; CHECK-NEXT:    [[I]] = add i32 [[PHI_I]], 1
; CHECK-NEXT:    [[GEP_FOR]] = getelementptr inbounds float, ptr [[PHI]], i32 0
; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ult i32 [[I]], 10
; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[FOR]], label [[END]]
; CHECK:       end:
; CHECK-NEXT:    [[PHI_END:%.*]] = phi ptr [ [[A_SROA_0]], [[ENTRY]] ], [ [[PHI]], [[FOR]] ]
; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[PHI_END]], align 4
; CHECK-NEXT:    ret i32 [[LOAD]]
;
entry:
  %a = alloca %pair, align 4
  %gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
  store float 1.0, ptr %gep_a, align 4
  br i1 %cond, label %for, label %end

for:
  %phi_i = phi i32 [ 0, %entry ], [ %i, %for ]
  %phi = phi ptr [ %gep_a, %entry], [ %gep_for, %for ]
  %i = add i32 %phi_i, 1
  %gep_for = getelementptr inbounds float, ptr %phi, i32 0
  %loop.cond = icmp ult i32 %i, 10
  br i1 %loop.cond, label %for, label %end

end:
  %phi_end = phi ptr [ %gep_a, %entry], [ %phi, %for ]
  %load = load i32, ptr %phi_end, align 4
  ret i32 %load
}

define void @unreachable_term(i1 %c1) {
; CHECK-LABEL: @unreachable_term(
; CHECK-NEXT:    [[A_SROA_0:%.*]] = alloca i32, align 4
; CHECK-NEXT:    unreachable
; CHECK:       bb1:
; CHECK-NEXT:    br label [[BB1_I:%.*]]
; CHECK:       bb1.i:
; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[A_SROA_0]], [[BB1:%.*]] ], [ null, [[BB1_I]] ]
; CHECK-NEXT:    store i32 0, ptr [[PHI]], align 1
; CHECK-NEXT:    br i1 [[C1:%.*]], label [[BB1_I]], label [[EXIT:%.*]]
; CHECK:       exit:
; CHECK-NEXT:    br label [[BB2:%.*]]
; CHECK:       bb2:
; CHECK-NEXT:    ret void
;
  %a = alloca [3 x i32], align 1
  unreachable

bb1:
  br label %bb1.i

bb1.i:
  %phi = phi ptr [ %a, %bb1 ], [ null, %bb1.i ]
  store i32 0, ptr %phi, align 1
  br i1 %c1, label %bb1.i, label %exit

exit:
  br label %bb2

bb2:
  ret void
}

define void @constant_value_phi(i1 %c1) {
; CHECK-LABEL: @constant_value_phi(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[LAND_LHS_TRUE_I:%.*]]
; CHECK:       land.lhs.true.i:
; CHECK-NEXT:    br i1 [[C1:%.*]], label [[COND_END_I:%.*]], label [[COND_END_I]]
; CHECK:       cond.end.i:
; CHECK-NEXT:    unreachable
;
entry:
  %s1 = alloca [3 x i16]
  %s = alloca [3 x i16]
  br label %land.lhs.true.i

land.lhs.true.i:                                  ; preds = %entry
  br i1 %c1, label %cond.end.i, label %cond.end.i

cond.end.i:                                       ; preds = %land.lhs.true.i, %land.lhs.true.i
  %.pre-phi1 = phi ptr [ %s1, %land.lhs.true.i ], [ %s1, %land.lhs.true.i ]
  call void @llvm.memcpy.p0.p0.i64(ptr %.pre-phi1, ptr %s, i64 3, i1 false)
  %load = load i16, ptr %s
  unreachable
}

define i32 @test_sroa_phi_gep_multiple_values_from_same_block(i32 %arg) {
; CHECK-LABEL: @test_sroa_phi_gep_multiple_values_from_same_block(
; CHECK-NEXT:  bb.1:
; CHECK-NEXT:    switch i32 [[ARG:%.*]], label [[BB_3:%.*]] [
; CHECK-NEXT:      i32 1, label [[BB_2:%.*]]
; CHECK-NEXT:      i32 2, label [[BB_2]]
; CHECK-NEXT:      i32 3, label [[BB_4:%.*]]
; CHECK-NEXT:      i32 4, label [[BB_4]]
; CHECK-NEXT:    ]
; CHECK:       bb.2:
; CHECK-NEXT:    br label [[BB_4]]
; CHECK:       bb.3:
; CHECK-NEXT:    br label [[BB_4]]
; CHECK:       bb.4:
; CHECK-NEXT:    [[PHI_SROA_PHI_SROA_SPECULATED:%.*]] = phi i32 [ undef, [[BB_3]] ], [ undef, [[BB_2]] ], [ undef, [[BB_1:%.*]] ], [ undef, [[BB_1]] ]
; CHECK-NEXT:    ret i32 [[PHI_SROA_PHI_SROA_SPECULATED]]
;
bb.1:
  %a = alloca %pair, align 4
  %b = alloca %pair, align 4
  switch i32 %arg, label %bb.3 [
  i32 1, label %bb.2
  i32 2, label %bb.2
  i32 3, label %bb.4
  i32 4, label %bb.4
  ]

bb.2:                                                ; preds = %bb.1, %bb.1
  br label %bb.4

bb.3:                                                ; preds = %bb.1
  br label %bb.4

bb.4:                                                ; preds = %bb.1, %bb.1, %bb.3, %bb.2
  %phi = phi ptr [ %a, %bb.3 ], [ %a, %bb.2 ], [ %b, %bb.1 ], [ %b, %bb.1 ]
  %gep = getelementptr inbounds %pair, ptr %phi, i32 0, i32 1
  %load = load i32, ptr %gep, align 4
  ret i32 %load
}

define i64 @test_phi_idx_mem2reg_const(i1 %arg) {
; CHECK-LABEL: @test_phi_idx_mem2reg_const(
; CHECK-NEXT:  bb:
; CHECK-NEXT:    br i1 [[ARG:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
; CHECK:       bb1:
; CHECK-NEXT:    br label [[END:%.*]]
; CHECK:       bb2:
; CHECK-NEXT:    br label [[END]]
; CHECK:       end:
; CHECK-NEXT:    [[PHI_SROA_PHI_SROA_SPECULATED:%.*]] = phi i64 [ 2, [[BB1]] ], [ 3, [[BB2]] ]
; CHECK-NEXT:    [[PHI:%.*]] = phi i64 [ 0, [[BB1]] ], [ 1, [[BB2]] ]
; CHECK-NEXT:    ret i64 [[PHI_SROA_PHI_SROA_SPECULATED]]
;
bb:
  %alloca = alloca [2 x i64], align 8
  %gep1 = getelementptr inbounds i64, ptr %alloca, i64 1
  store i64 2, ptr %alloca
  store i64 3, ptr %gep1
  br i1 %arg, label %bb1, label %bb2

bb1:
  br label %end

bb2:
  br label %end

end:
  %phi = phi i64 [ 0, %bb1 ], [ 1, %bb2 ]
  %getelementptr = getelementptr inbounds i64, ptr %alloca, i64 %phi
  %load = load i64, ptr %getelementptr
  ret i64 %load
}

define i64 @test_phi_idx_mem2reg_not_const(i1 %arg, i64 %idx) {
; CHECK-LABEL: @test_phi_idx_mem2reg_not_const(
; CHECK-NEXT:  bb:
; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca [2 x i64], align 8
; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds i64, ptr [[ALLOCA]], i64 1
; CHECK-NEXT:    store i64 2, ptr [[ALLOCA]], align 4
; CHECK-NEXT:    store i64 3, ptr [[GEP1]], align 4
; CHECK-NEXT:    br i1 [[ARG:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
; CHECK:       bb1:
; CHECK-NEXT:    br label [[END:%.*]]
; CHECK:       bb2:
; CHECK-NEXT:    br label [[END]]
; CHECK:       end:
; CHECK-NEXT:    [[PHI:%.*]] = phi i64 [ 0, [[BB1]] ], [ [[IDX:%.*]], [[BB2]] ]
; CHECK-NEXT:    [[GETELEMENTPTR:%.*]] = getelementptr inbounds i64, ptr [[ALLOCA]], i64 [[PHI]]
; CHECK-NEXT:    [[LOAD:%.*]] = load i64, ptr [[GETELEMENTPTR]], align 4
; CHECK-NEXT:    ret i64 [[LOAD]]
;
bb:
  %alloca = alloca [2 x i64], align 8
  %gep1 = getelementptr inbounds i64, ptr %alloca, i64 1
  store i64 2, ptr %alloca
  store i64 3, ptr %gep1
  br i1 %arg, label %bb1, label %bb2

bb1:
  br label %end

bb2:
  br label %end

end:
  %phi = phi i64 [ 0, %bb1 ], [ %idx, %bb2 ]
  %getelementptr = getelementptr inbounds i64, ptr %alloca, i64 %phi
  %load = load i64, ptr %getelementptr
  ret i64 %load
}

define i64 @test_phi_mem2reg_pointer_op_is_non_const_gep(i1 %arg, i64 %idx) {
; CHECK-LABEL: @test_phi_mem2reg_pointer_op_is_non_const_gep(
; CHECK-NEXT:  bb:
; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca [2 x i64], align 8
; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds i64, ptr [[ALLOCA]], i64 1
; CHECK-NEXT:    store i64 2, ptr [[ALLOCA]], align 4
; CHECK-NEXT:    store i64 3, ptr [[GEP1]], align 4
; CHECK-NEXT:    br i1 [[ARG:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
; CHECK:       bb1:
; CHECK-NEXT:    br label [[END:%.*]]
; CHECK:       bb2:
; CHECK-NEXT:    br label [[END]]
; CHECK:       end:
; CHECK-NEXT:    [[PHI:%.*]] = phi i64 [ 0, [[BB1]] ], [ 1, [[BB2]] ]
; CHECK-NEXT:    [[GETELEMENTPTR:%.*]] = getelementptr inbounds i64, ptr [[ALLOCA]], i64 [[IDX:%.*]]
; CHECK-NEXT:    [[GETELEMENTPTR2:%.*]] = getelementptr inbounds i64, ptr [[GETELEMENTPTR]], i64 [[PHI]]
; CHECK-NEXT:    [[LOAD:%.*]] = load i64, ptr [[GETELEMENTPTR]], align 4
; CHECK-NEXT:    ret i64 [[LOAD]]
;
bb:
  %alloca = alloca [2 x i64], align 8
  %gep1 = getelementptr inbounds i64, ptr %alloca, i64 1
  store i64 2, ptr %alloca
  store i64 3, ptr %gep1
  br i1 %arg, label %bb1, label %bb2

bb1:
  br label %end

bb2:
  br label %end

end:
  %phi = phi i64 [ 0, %bb1 ], [ 1, %bb2 ]
  %getelementptr = getelementptr inbounds i64, ptr %alloca, i64 %idx
  %getelementptr2 = getelementptr inbounds i64, ptr %getelementptr, i64 %phi
  %load = load i64, ptr %getelementptr
  ret i64 %load
}

define i1 @test_phi_mem2reg_entry_block_alloca_not_at_beginning(i1 %arg) {
; CHECK-LABEL: @test_phi_mem2reg_entry_block_alloca_not_at_beginning(
; CHECK-NEXT:  bb:
; CHECK-NEXT:    call void @f()
; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca i64, align 8
; CHECK-NEXT:    [[PHI_SROA_GEP:%.*]] = getelementptr i64, ptr [[ALLOCA]], i64 1
; CHECK-NEXT:    [[PHI_SROA_GEP1:%.*]] = getelementptr i64, ptr [[ALLOCA]], i64 2
; CHECK-NEXT:    br i1 [[ARG:%.*]], label [[BB2:%.*]], label [[BB3:%.*]]
; CHECK:       bb2:
; CHECK-NEXT:    br label [[BB3]]
; CHECK:       bb3:
; CHECK-NEXT:    [[PHI_SROA_PHI:%.*]] = phi ptr [ [[PHI_SROA_GEP]], [[BB:%.*]] ], [ [[PHI_SROA_GEP1]], [[BB2]] ]
; CHECK-NEXT:    [[PHI:%.*]] = phi i64 [ 1, [[BB]] ], [ 2, [[BB2]] ]
; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq ptr [[PHI_SROA_PHI]], null
; CHECK-NEXT:    ret i1 [[ICMP]]
;
bb:
  call void @f()
  %alloca = alloca i64
  br i1 %arg, label %bb2, label %bb3
bb2:
  br label %bb3
bb3:
  %phi = phi i64 [ 1, %bb ], [ 2, %bb2 ]
  %gep = getelementptr i64, ptr %alloca, i64 %phi
  %icmp = icmp eq ptr %gep, null
  ret i1 %icmp
}

define i32 @test_phi_mem2reg_alloca_not_in_entry_block(i1 %arg) {
; CHECK-LABEL: @test_phi_mem2reg_alloca_not_in_entry_block(
; CHECK-NEXT:  bb:
; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca i64, align 8
; CHECK-NEXT:    store i64 123, ptr [[ALLOCA]], align 4
; CHECK-NEXT:    br label [[BB2:%.*]]
; CHECK:       bb2:
; CHECK-NEXT:    [[ALLOCA2:%.*]] = alloca i64, align 8
; CHECK-NEXT:    store i64 124, ptr [[ALLOCA]], align 4
; CHECK-NEXT:    br i1 [[ARG:%.*]], label [[BB3:%.*]], label [[BB4:%.*]]
; CHECK:       bb3:
; CHECK-NEXT:    br label [[BB4]]
; CHECK:       bb4:
; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[ALLOCA]], [[BB2]] ], [ [[ALLOCA2]], [[BB3]] ]
; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i32, ptr [[PHI]], i64 1
; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT:    ret i32 [[LOAD]]
;
bb:
  %alloca = alloca i64
  store i64 123, ptr %alloca
  br label %bb2
bb2:
  %alloca2 = alloca i64
  store i64 124, ptr %alloca
  br i1 %arg, label %bb3, label %bb4
bb3:
  br label %bb4
bb4:
  %phi = phi ptr [ %alloca, %bb2 ], [ %alloca2, %bb3 ]
  %gep = getelementptr i32, ptr %phi, i64 1
  %load = load i32, ptr %gep
  ret i32 %load
}

define i64 @test_unfold_phi_duplicate_phi_entry(ptr %arg, i8 %arg1, i1 %arg2) {
; CHECK-LABEL: @test_unfold_phi_duplicate_phi_entry(
; CHECK-NEXT:  bb:
; CHECK-NEXT:    [[ALLOCA_SROA_0:%.*]] = alloca i64, align 8
; CHECK-NEXT:    [[PHI_SROA_GEP:%.*]] = getelementptr i64, ptr [[ARG:%.*]], i64 1
; CHECK-NEXT:    br i1 [[ARG2:%.*]], label [[BB5:%.*]], label [[BB3:%.*]]
; CHECK:       bb3:
; CHECK-NEXT:    switch i8 [[ARG1:%.*]], label [[BB4:%.*]] [
; CHECK-NEXT:      i8 0, label [[BB5]]
; CHECK-NEXT:      i8 1, label [[BB5]]
; CHECK-NEXT:    ]
; CHECK:       bb4:
; CHECK-NEXT:    ret i64 0
; CHECK:       bb5:
; CHECK-NEXT:    [[PHI_SROA_PHI:%.*]] = phi ptr [ [[PHI_SROA_GEP]], [[BB3]] ], [ [[PHI_SROA_GEP]], [[BB3]] ], [ [[ALLOCA_SROA_0]], [[BB:%.*]] ]
; CHECK-NEXT:    [[LOAD:%.*]] = load i64, ptr [[PHI_SROA_PHI]], align 4
; CHECK-NEXT:    ret i64 [[LOAD]]
;
bb:
  %alloca = alloca [2 x i64], align 8
  br i1 %arg2, label %bb5, label %bb3

bb3:                                              ; preds = %bb
  switch i8 %arg1, label %bb4 [
  i8 0, label %bb5
  i8 1, label %bb5
  ]

bb4:                                              ; preds = %bb5, %bb3
  ret i64 0

bb5:                                              ; preds = %bb3, %bb3, %bb
  %phi = phi ptr [ %arg, %bb3 ], [ %arg, %bb3 ], [ %alloca, %bb ]
  %getelementptr = getelementptr i64, ptr %phi, i64 1
  %load = load i64, ptr %getelementptr
  ret i64 %load
}

declare void @f()

declare ptr @foo()

declare i32 @__gxx_personality_v0(...)

declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg)
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CHECK-MODIFY-CFG: {{.*}}
; CHECK-PRESERVE-CFG: {{.*}}