llvm/llvm/test/Transforms/SimplifyCFG/X86/sink-common-code.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -sink-common-insts -S | FileCheck %s
; RUN: opt --try-experimental-debuginfo-iterators < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -sink-common-insts -S | FileCheck %s
; RUN: opt < %s -passes='simplifycfg<sink-common-insts>' -S | FileCheck %s
; RUN: opt --try-experimental-debuginfo-iterators < %s -passes='simplifycfg<sink-common-insts>' -S | FileCheck %s

target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-pc-linux-gnu"

define zeroext i1 @test1(i1 zeroext %flag, i32 %blksA, i32 %blksB, i32 %nblks) {
; CHECK-LABEL: @test1(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[NBLKS:%.*]], [[BLKSB:%.*]]
; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i32 [[ADD]], [[BLKSA:%.*]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[BLKSA]], [[NBLKS]]
; CHECK-NEXT:    [[CMP2_SINK:%.*]] = select i1 [[FLAG:%.*]], i1 [[CMP]], i1 [[CMP2]]
; CHECK-NEXT:    [[FROMBOOL3:%.*]] = zext i1 [[CMP2_SINK]] to i8
; CHECK-NEXT:    [[TOBOOL4:%.*]] = icmp ne i8 [[FROMBOOL3]], 0
; CHECK-NEXT:    ret i1 [[TOBOOL4]]
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %cmp = icmp uge i32 %blksA, %nblks
  %frombool1 = zext i1 %cmp to i8
  br label %if.end

if.else:
  %add = add i32 %nblks, %blksB
  %cmp2 = icmp ule i32 %add, %blksA
  %frombool3 = zext i1 %cmp2 to i8
  br label %if.end

if.end:
  %obeys.0 = phi i8 [ %frombool1, %if.then ], [ %frombool3, %if.else ]
  %tobool4 = icmp ne i8 %obeys.0, 0
  ret i1 %tobool4
}

define zeroext i1 @test2(i1 zeroext %flag, i32 %blksA, i32 %blksB, i32 %nblks) {
; CHECK-LABEL: @test2(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[NBLKS:%.*]], [[BLKSB:%.*]]
; CHECK-NEXT:    [[ADD_SINK:%.*]] = select i1 [[FLAG:%.*]], i32 [[NBLKS]], i32 [[ADD]]
; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i32 [[BLKSA:%.*]], [[ADD_SINK]]
; CHECK-NEXT:    [[FROMBOOL3:%.*]] = zext i1 [[CMP2]] to i8
; CHECK-NEXT:    [[TOBOOL4:%.*]] = icmp ne i8 [[FROMBOOL3]], 0
; CHECK-NEXT:    ret i1 [[TOBOOL4]]
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %cmp = icmp uge i32 %blksA, %nblks
  %frombool1 = zext i1 %cmp to i8
  br label %if.end

if.else:
  %add = add i32 %nblks, %blksB
  %cmp2 = icmp uge i32 %blksA, %add
  %frombool3 = zext i1 %cmp2 to i8
  br label %if.end

if.end:
  %obeys.0 = phi i8 [ %frombool1, %if.then ], [ %frombool3, %if.else ]
  %tobool4 = icmp ne i8 %obeys.0, 0
  ret i1 %tobool4
}

declare i32 @foo(i32, i32) nounwind readnone

define i32 @test3(i1 zeroext %flag, i32 %x, i32 %y) {
; CHECK-LABEL: @test3(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[X_Y:%.*]] = select i1 [[FLAG:%.*]], i32 [[X:%.*]], i32 [[Y:%.*]]
; CHECK-NEXT:    [[X1:%.*]] = call i32 @foo(i32 [[X_Y]], i32 0) #[[ATTR0:[0-9]+]]
; CHECK-NEXT:    [[Y1:%.*]] = call i32 @foo(i32 [[X_Y]], i32 1) #[[ATTR0]]
; CHECK-NEXT:    [[RET:%.*]] = add i32 [[X1]], [[Y1]]
; CHECK-NEXT:    ret i32 [[RET]]
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %x0 = call i32 @foo(i32 %x, i32 0) nounwind readnone
  %y0 = call i32 @foo(i32 %x, i32 1) nounwind readnone
  br label %if.end

if.else:
  %x1 = call i32 @foo(i32 %y, i32 0) nounwind readnone
  %y1 = call i32 @foo(i32 %y, i32 1) nounwind readnone
  br label %if.end

if.end:
  %xx = phi i32 [ %x0, %if.then ], [ %x1, %if.else ]
  %yy = phi i32 [ %y0, %if.then ], [ %y1, %if.else ]
  %ret = add i32 %xx, %yy
  ret i32 %ret
}


define i32 @test4(i1 zeroext %flag, i32 %x, ptr %y) {
; CHECK-LABEL: @test4(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[DOT:%.*]] = select i1 [[FLAG:%.*]], i32 5, i32 7
; CHECK-NEXT:    [[B:%.*]] = add i32 [[X:%.*]], [[DOT]]
; CHECK-NEXT:    store i32 [[B]], ptr [[Y:%.*]], align 4
; CHECK-NEXT:    ret i32 1
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %a = add i32 %x, 5
  store i32 %a, ptr %y
  br label %if.end

if.else:
  %b = add i32 %x, 7
  store i32 %b, ptr %y
  br label %if.end

if.end:
  ret i32 1
}


define i32 @test5(i1 zeroext %flag, i32 %x, ptr %y) {
; CHECK-LABEL: @test5(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[A:%.*]] = add i32 [[X:%.*]], 5
; CHECK-NEXT:    store volatile i32 [[A]], ptr [[Y:%.*]], align 4
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    [[B:%.*]] = add i32 [[X]], 7
; CHECK-NEXT:    store i32 [[B]], ptr [[Y]], align 4
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    ret i32 1
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %a = add i32 %x, 5
  store volatile i32 %a, ptr %y
  br label %if.end

if.else:
  %b = add i32 %x, 7
  store i32 %b, ptr %y
  br label %if.end

if.end:
  ret i32 1
}


define i32 @test6(i1 zeroext %flag, i32 %x, ptr %y) {
; CHECK-LABEL: @test6(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[DOT:%.*]] = select i1 [[FLAG:%.*]], i32 5, i32 7
; CHECK-NEXT:    [[B:%.*]] = add i32 [[X:%.*]], [[DOT]]
; CHECK-NEXT:    store volatile i32 [[B]], ptr [[Y:%.*]], align 4
; CHECK-NEXT:    ret i32 1
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %a = add i32 %x, 5
  store volatile i32 %a, ptr %y
  br label %if.end

if.else:
  %b = add i32 %x, 7
  store volatile i32 %b, ptr %y
  br label %if.end

if.end:
  ret i32 1
}


define i32 @test7(i1 zeroext %flag, i32 %x, ptr %y) {
; CHECK-LABEL: @test7(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[DOT:%.*]] = select i1 [[FLAG:%.*]], i32 5, i32 7
; CHECK-NEXT:    [[W:%.*]] = load volatile i32, ptr [[Y:%.*]], align 4
; CHECK-NEXT:    [[B:%.*]] = add i32 [[W]], [[DOT]]
; CHECK-NEXT:    store volatile i32 [[B]], ptr [[Y]], align 4
; CHECK-NEXT:    ret i32 1
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %z = load volatile i32, ptr %y
  %a = add i32 %z, 5
  store volatile i32 %a, ptr %y
  br label %if.end

if.else:
  %w = load volatile i32, ptr %y
  %b = add i32 %w, 7
  store volatile i32 %b, ptr %y
  br label %if.end

if.end:
  ret i32 1
}


; %z and %w are in different blocks. We shouldn't sink the add because
; there may be intervening memory instructions.
define i32 @test8(i1 zeroext %flag, i32 %x, ptr %y) {
; CHECK-LABEL: @test8(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[Z:%.*]] = load volatile i32, ptr [[Y:%.*]], align 4
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[A:%.*]] = add i32 [[Z]], 5
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    [[W:%.*]] = load volatile i32, ptr [[Y]], align 4
; CHECK-NEXT:    [[B:%.*]] = add i32 [[W]], 7
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[B_SINK:%.*]] = phi i32 [ [[B]], [[IF_ELSE]] ], [ [[A]], [[IF_THEN]] ]
; CHECK-NEXT:    store volatile i32 [[B_SINK]], ptr [[Y]], align 4
; CHECK-NEXT:    ret i32 1
;
entry:
  %z = load volatile i32, ptr %y
  br i1 %flag, label %if.then, label %if.else

if.then:
  %a = add i32 %z, 5
  store volatile i32 %a, ptr %y
  br label %if.end

if.else:
  %w = load volatile i32, ptr %y
  %b = add i32 %w, 7
  store volatile i32 %b, ptr %y
  br label %if.end

if.end:
  ret i32 1
}


; The extra store in %if.then means %z and %w are not equivalent.
define i32 @test9(i1 zeroext %flag, i32 %x, ptr %y, ptr %p) {
; CHECK-LABEL: @test9(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    store i32 7, ptr [[P:%.*]], align 4
; CHECK-NEXT:    [[Z:%.*]] = load volatile i32, ptr [[Y:%.*]], align 4
; CHECK-NEXT:    store i32 6, ptr [[P]], align 4
; CHECK-NEXT:    [[A:%.*]] = add i32 [[Z]], 5
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    [[W:%.*]] = load volatile i32, ptr [[Y]], align 4
; CHECK-NEXT:    [[B:%.*]] = add i32 [[W]], 7
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[B_SINK:%.*]] = phi i32 [ [[B]], [[IF_ELSE]] ], [ [[A]], [[IF_THEN]] ]
; CHECK-NEXT:    store volatile i32 [[B_SINK]], ptr [[Y]], align 4
; CHECK-NEXT:    ret i32 1
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  store i32 7, ptr %p
  %z = load volatile i32, ptr %y
  store i32 6, ptr %p
  %a = add i32 %z, 5
  store volatile i32 %a, ptr %y
  br label %if.end

if.else:
  %w = load volatile i32, ptr %y
  %b = add i32 %w, 7
  store volatile i32 %b, ptr %y
  br label %if.end

if.end:
  ret i32 1
}


%struct.anon = type { i32, i32 }

; The GEP indexes a struct type so cannot have a variable last index.
define i32 @test10(i1 zeroext %flag, i32 %x, ptr %y, ptr %s) {
; CHECK-LABEL: @test10(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    call void @bar(i32 5)
; CHECK-NEXT:    store volatile i32 [[X:%.*]], ptr [[S:%.*]], align 4
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    call void @bar(i32 6)
; CHECK-NEXT:    [[GEPB:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], ptr [[S]], i32 0, i32 1
; CHECK-NEXT:    store volatile i32 [[X]], ptr [[GEPB]], align 4
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    ret i32 1
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  call void @bar(i32 5)
  store volatile i32 %x, ptr %s
  br label %if.end

if.else:
  call void @bar(i32 6)
  %gepb = getelementptr inbounds %struct.anon, ptr %s, i32 0, i32 1
  store volatile i32 %x, ptr %gepb
  br label %if.end

if.end:
  ret i32 1
}


; The shufflevector's mask operand cannot be merged in a PHI.
define i32 @test11(i1 zeroext %flag, i32 %w, <2 x i32> %x, <2 x i32> %y) {
; CHECK-LABEL: @test11(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[DUMMY:%.*]] = add i32 [[W:%.*]], 5
; CHECK-NEXT:    [[SV1:%.*]] = shufflevector <2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]], <2 x i32> <i32 0, i32 1>
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    [[DUMMY1:%.*]] = add i32 [[W]], 6
; CHECK-NEXT:    [[SV2:%.*]] = shufflevector <2 x i32> [[X]], <2 x i32> [[Y]], <2 x i32> <i32 1, i32 0>
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[P:%.*]] = phi <2 x i32> [ [[SV1]], [[IF_THEN]] ], [ [[SV2]], [[IF_ELSE]] ]
; CHECK-NEXT:    ret i32 1
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %dummy = add i32 %w, 5
  %sv1 = shufflevector <2 x i32> %x, <2 x i32> %y, <2 x i32> <i32 0, i32 1>
  br label %if.end

if.else:
  %dummy1 = add i32 %w, 6
  %sv2 = shufflevector <2 x i32> %x, <2 x i32> %y, <2 x i32> <i32 1, i32 0>
  br label %if.end

if.end:
  %p = phi <2 x i32> [ %sv1, %if.then ], [ %sv2, %if.else ]
  ret i32 1
}


; We can't common an intrinsic!
define i32 @test12(i1 zeroext %flag, i32 %w, i32 %x, i32 %y) {
; CHECK-LABEL: @test12(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[DUMMY:%.*]] = add i32 [[W:%.*]], 5
; CHECK-NEXT:    [[SV1:%.*]] = call i32 @llvm.ctlz.i32(i32 [[X:%.*]], i1 false)
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    [[DUMMY1:%.*]] = add i32 [[W]], 6
; CHECK-NEXT:    [[SV2:%.*]] = call i32 @llvm.cttz.i32(i32 [[X]], i1 false)
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[P:%.*]] = phi i32 [ [[SV1]], [[IF_THEN]] ], [ [[SV2]], [[IF_ELSE]] ]
; CHECK-NEXT:    ret i32 1
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %dummy = add i32 %w, 5
  %sv1 = call i32 @llvm.ctlz.i32(i32 %x, i1 false)
  br label %if.end

if.else:
  %dummy1 = add i32 %w, 6
  %sv2 = call i32 @llvm.cttz.i32(i32 %x, i1 false)
  br label %if.end

if.end:
  %p = phi i32 [ %sv1, %if.then ], [ %sv2, %if.else ]
  ret i32 1
}

declare i32 @llvm.ctlz.i32(i32 %x, i1 immarg) readnone
declare i32 @llvm.cttz.i32(i32 %x, i1 immarg) readnone


; The TBAA metadata should be properly combined.
define i32 @test13(i1 zeroext %flag, i32 %x, ptr %y) {
; CHECK-LABEL: @test13(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[DOT:%.*]] = select i1 [[FLAG:%.*]], i32 5, i32 7
; CHECK-NEXT:    [[W:%.*]] = load volatile i32, ptr [[Y:%.*]], align 4
; CHECK-NEXT:    [[B:%.*]] = add i32 [[W]], [[DOT]]
; CHECK-NEXT:    store volatile i32 [[B]], ptr [[Y]], align 4, !tbaa [[TBAA4:![0-9]+]]
; CHECK-NEXT:    ret i32 1
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %z = load volatile i32, ptr %y
  %a = add i32 %z, 5
  store volatile i32 %a, ptr %y, !tbaa !3
  br label %if.end

if.else:
  %w = load volatile i32, ptr %y
  %b = add i32 %w, 7
  store volatile i32 %b, ptr %y, !tbaa !4
  br label %if.end

if.end:
  ret i32 1
}

!0 = !{ !"an example type tree" }
!1 = !{ !"int", !0 }
!2 = !{ !"float", !0 }
!3 = !{ !"const float", !2, i64 0 }
!4 = !{ !"special float", !2, i64 1 }


; The call should be commoned.
define i32 @test13a(i1 zeroext %flag, i32 %w, i32 %x, i32 %y) {
; CHECK-LABEL: @test13a(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[X_Y:%.*]] = select i1 [[FLAG:%.*]], i32 [[X:%.*]], i32 [[Y:%.*]]
; CHECK-NEXT:    [[SV2:%.*]] = call i32 @bar(i32 [[X_Y]])
; CHECK-NEXT:    ret i32 1
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %sv1 = call i32 @bar(i32 %x)
  br label %if.end

if.else:
  %sv2 = call i32 @bar(i32 %y)
  br label %if.end

if.end:
  %p = phi i32 [ %sv1, %if.then ], [ %sv2, %if.else ]
  ret i32 1
}
declare i32 @bar(i32)


; The load should be commoned.
define i32 @test14(i1 zeroext %flag, i32 %w, i32 %x, i32 %y, ptr %s) {
; CHECK-LABEL: @test14(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[DOT:%.*]] = select i1 [[FLAG:%.*]], i32 1, i32 4
; CHECK-NEXT:    [[DOT2:%.*]] = select i1 [[FLAG]], i32 56, i32 57
; CHECK-NEXT:    [[DUMMY2:%.*]] = add i32 [[X:%.*]], [[DOT]]
; CHECK-NEXT:    [[GEPB:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], ptr [[S:%.*]], i32 0, i32 1
; CHECK-NEXT:    [[SV2:%.*]] = load i32, ptr [[GEPB]], align 4
; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[SV2]], [[DOT2]]
; CHECK-NEXT:    ret i32 1
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %dummy = add i32 %x, 1
  %gepa = getelementptr inbounds %struct.anon, ptr %s, i32 0, i32 1
  %sv1 = load i32, ptr %gepa
  %cmp1 = icmp eq i32 %sv1, 56
  br label %if.end

if.else:
  %dummy2 = add i32 %x, 4
  %gepb = getelementptr inbounds %struct.anon, ptr %s, i32 0, i32 1
  %sv2 = load i32, ptr %gepb
  %cmp2 = icmp eq i32 %sv2, 57
  call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
  br label %if.end

if.end:
  %p = phi i1 [ %cmp1, %if.then ], [ %cmp2, %if.else ]
  ret i32 1
}

declare void @llvm.dbg.value(metadata, metadata, metadata)
!llvm.module.flags = !{!5, !6}
!llvm.dbg.cu = !{!7}

!5 = !{i32 2, !"Dwarf Version", i32 4}
!6 = !{i32 2, !"Debug Info Version", i32 3}
!7 = distinct !DICompileUnit(language: DW_LANG_C99, file: !10)
!8 = distinct !DISubprogram(name: "foo", unit: !7)
!9 = !DILocalVariable(name: "b", line: 1, arg: 2, scope: !8)
!10 = !DIFile(filename: "a.c", directory: "a/b")
!11 = !DILocation(line: 1, column: 14, scope: !8)


; The load should not be commoned, as it will get separated from the GEP
; instruction producing the address.
define i32 @test15(i1 zeroext %flag, i32 %w, i32 %x, i32 %y, ptr %s) {
; CHECK-LABEL: @test15(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    call void @bar(i32 1)
; CHECK-NEXT:    [[SV1:%.*]] = load i32, ptr [[S:%.*]], align 4
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    call void @bar(i32 4)
; CHECK-NEXT:    [[GEPB:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], ptr [[S]], i32 0, i32 1
; CHECK-NEXT:    [[SV2:%.*]] = load i32, ptr [[GEPB]], align 4
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[SV2_SINK:%.*]] = phi i32 [ [[SV2]], [[IF_ELSE]] ], [ [[SV1]], [[IF_THEN]] ]
; CHECK-NEXT:    [[DOTSINK:%.*]] = phi i64 [ 57, [[IF_ELSE]] ], [ 56, [[IF_THEN]] ]
; CHECK-NEXT:    [[EXT2:%.*]] = zext i32 [[SV2_SINK]] to i64
; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i64 [[EXT2]], [[DOTSINK]]
; CHECK-NEXT:    ret i32 1
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  call void @bar(i32 1)
  %sv1 = load i32, ptr %s
  %ext1 = zext i32 %sv1 to i64
  %cmp1 = icmp eq i64 %ext1, 56
  br label %if.end

if.else:
  call void @bar(i32 4)
  %gepb = getelementptr inbounds %struct.anon, ptr %s, i32 0, i32 1
  %sv2 = load i32, ptr %gepb
  %ext2 = zext i32 %sv2 to i64
  %cmp2 = icmp eq i64 %ext2, 57
  br label %if.end

if.end:
  %p = phi i1 [ %cmp1, %if.then ], [ %cmp2, %if.else ]
  ret i32 1
}


define zeroext i1 @test_crash(i1 zeroext %flag, ptr %i4, ptr %m, ptr %n) {
; CHECK-LABEL: @test_crash(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[I4:%.*]], align 4
; CHECK-NEXT:    [[TMP2:%.*]] = add i32 [[TMP1]], -1
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    [[TMP3:%.*]] = load i32, ptr [[M:%.*]], align 4
; CHECK-NEXT:    [[TMP4:%.*]] = load i32, ptr [[N:%.*]], align 4
; CHECK-NEXT:    [[TMP5:%.*]] = add i32 [[TMP3]], [[TMP4]]
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[TMP5_SINK:%.*]] = phi i32 [ [[TMP5]], [[IF_ELSE]] ], [ [[TMP2]], [[IF_THEN]] ]
; CHECK-NEXT:    store i32 [[TMP5_SINK]], ptr [[I4]], align 4
; CHECK-NEXT:    ret i1 true
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %tmp1 = load i32, ptr %i4
  %tmp2 = add i32 %tmp1, -1
  store i32 %tmp2, ptr %i4
  br label %if.end

if.else:
  %tmp3 = load i32, ptr %m
  %tmp4 = load i32, ptr %n
  %tmp5 = add i32 %tmp3, %tmp4
  store i32 %tmp5, ptr %i4
  br label %if.end

if.end:
  ret i1 true
}

; No checks for test_crash - just ensure it doesn't crash!

define zeroext i1 @test16(i1 zeroext %flag, i1 zeroext %flag2, i32 %blksA, i32 %blksB, i32 %nblks) {
; CHECK-LABEL: @test16(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[BLKSA:%.*]], [[NBLKS:%.*]]
; CHECK-NEXT:    [[FROMBOOL1:%.*]] = zext i1 [[CMP]] to i8
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    br i1 [[FLAG2:%.*]], label [[IF_THEN2:%.*]], label [[IF_END]]
; CHECK:       if.then2:
; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[NBLKS]], [[BLKSB:%.*]]
; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i32 [[ADD]], [[BLKSA]]
; CHECK-NEXT:    [[FROMBOOL3:%.*]] = zext i1 [[CMP2]] to i8
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[OBEYS_0:%.*]] = phi i8 [ [[FROMBOOL1]], [[IF_THEN]] ], [ [[FROMBOOL3]], [[IF_THEN2]] ], [ 0, [[IF_ELSE]] ]
; CHECK-NEXT:    [[TOBOOL4:%.*]] = icmp ne i8 [[OBEYS_0]], 0
; CHECK-NEXT:    ret i1 [[TOBOOL4]]
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %cmp = icmp uge i32 %blksA, %nblks
  %frombool1 = zext i1 %cmp to i8
  br label %if.end

if.else:
  br i1 %flag2, label %if.then2, label %if.end

if.then2:
  %add = add i32 %nblks, %blksB
  %cmp2 = icmp ule i32 %add, %blksA
  %frombool3 = zext i1 %cmp2 to i8
  br label %if.end

if.end:
  %obeys.0 = phi i8 [ %frombool1, %if.then ], [ %frombool3, %if.then2 ], [ 0, %if.else ]
  %tobool4 = icmp ne i8 %obeys.0, 0
  ret i1 %tobool4
}


define zeroext i1 @test16a(i1 zeroext %flag, i1 zeroext %flag2, i32 %blksA, i32 %blksB, i32 %nblks, ptr %p) {
; CHECK-LABEL: @test16a(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[BLKSA:%.*]], [[NBLKS:%.*]]
; CHECK-NEXT:    br label [[IF_END_SINK_SPLIT:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    br i1 [[FLAG2:%.*]], label [[IF_THEN2:%.*]], label [[IF_END:%.*]]
; CHECK:       if.then2:
; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[NBLKS]], [[BLKSB:%.*]]
; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i32 [[ADD]], [[BLKSA]]
; CHECK-NEXT:    br label [[IF_END_SINK_SPLIT]]
; CHECK:       if.end.sink.split:
; CHECK-NEXT:    [[CMP2_SINK:%.*]] = phi i1 [ [[CMP2]], [[IF_THEN2]] ], [ [[CMP]], [[IF_THEN]] ]
; CHECK-NEXT:    [[FROMBOOL3:%.*]] = zext i1 [[CMP2_SINK]] to i8
; CHECK-NEXT:    store i8 [[FROMBOOL3]], ptr [[P:%.*]], align 1
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    ret i1 true
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %cmp = icmp uge i32 %blksA, %nblks
  %frombool1 = zext i1 %cmp to i8
  store i8 %frombool1, ptr %p
  br label %if.end

if.else:
  br i1 %flag2, label %if.then2, label %if.end

if.then2:
  %add = add i32 %nblks, %blksB
  %cmp2 = icmp ule i32 %add, %blksA
  %frombool3 = zext i1 %cmp2 to i8
  store i8 %frombool3, ptr %p
  br label %if.end

if.end:
  ret i1 true
}


define zeroext i1 @test17(i32 %flag, i32 %blksA, i32 %blksB, i32 %nblks) {
; CHECK-LABEL: @test17(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    switch i32 [[FLAG:%.*]], label [[IF_END:%.*]] [
; CHECK-NEXT:      i32 0, label [[IF_THEN:%.*]]
; CHECK-NEXT:      i32 1, label [[IF_THEN2:%.*]]
; CHECK-NEXT:    ]
; CHECK:       if.then:
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[BLKSA:%.*]], [[NBLKS:%.*]]
; CHECK-NEXT:    br label [[IF_END_SINK_SPLIT:%.*]]
; CHECK:       if.then2:
; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[NBLKS]], [[BLKSB:%.*]]
; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i32 [[ADD]], [[BLKSA]]
; CHECK-NEXT:    br label [[IF_END_SINK_SPLIT]]
; CHECK:       if.end.sink.split:
; CHECK-NEXT:    [[CMP2_SINK:%.*]] = phi i1 [ [[CMP2]], [[IF_THEN2]] ], [ [[CMP]], [[IF_THEN]] ]
; CHECK-NEXT:    [[FROMBOOL3:%.*]] = call i8 @i1toi8(i1 [[CMP2_SINK]])
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[OBEYS_0:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[FROMBOOL3]], [[IF_END_SINK_SPLIT]] ]
; CHECK-NEXT:    [[TOBOOL4:%.*]] = icmp ne i8 [[OBEYS_0]], 0
; CHECK-NEXT:    ret i1 [[TOBOOL4]]
;
entry:
  switch i32 %flag, label %if.end [
  i32 0, label %if.then
  i32 1, label %if.then2
  ]

if.then:
  %cmp = icmp uge i32 %blksA, %nblks
  %frombool1 = call i8 @i1toi8(i1 %cmp)
  br label %if.end

if.then2:
  %add = add i32 %nblks, %blksB
  %cmp2 = icmp ule i32 %add, %blksA
  %frombool3 = call i8 @i1toi8(i1 %cmp2)
  br label %if.end

if.end:
  %obeys.0 = phi i8 [ %frombool1, %if.then ], [ %frombool3, %if.then2 ], [ 0, %entry ]
  %tobool4 = icmp ne i8 %obeys.0, 0
  ret i1 %tobool4
}
declare i8 @i1toi8(i1)





define zeroext i1 @test18(i32 %flag, i32 %blksA, i32 %blksB, i32 %nblks) {
; CHECK-LABEL: @test18(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    switch i32 [[FLAG:%.*]], label [[IF_THEN3:%.*]] [
; CHECK-NEXT:      i32 0, label [[IF_THEN:%.*]]
; CHECK-NEXT:      i32 1, label [[IF_THEN2:%.*]]
; CHECK-NEXT:    ]
; CHECK:       if.then:
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[BLKSA:%.*]], [[NBLKS:%.*]]
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.then2:
; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[NBLKS]], [[BLKSB:%.*]]
; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i32 [[ADD]], [[BLKSA]]
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.then3:
; CHECK-NEXT:    [[ADD2:%.*]] = add i32 [[NBLKS]], [[BLKSA]]
; CHECK-NEXT:    [[CMP3:%.*]] = icmp ule i32 [[ADD2]], [[BLKSA]]
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[CMP3_SINK:%.*]] = phi i1 [ [[CMP3]], [[IF_THEN3]] ], [ [[CMP2]], [[IF_THEN2]] ], [ [[CMP]], [[IF_THEN]] ]
; CHECK-NEXT:    [[FROMBOOL4:%.*]] = zext i1 [[CMP3_SINK]] to i8
; CHECK-NEXT:    [[TOBOOL4:%.*]] = icmp ne i8 [[FROMBOOL4]], 0
; CHECK-NEXT:    ret i1 [[TOBOOL4]]
;
entry:
  switch i32 %flag, label %if.then3 [
  i32 0, label %if.then
  i32 1, label %if.then2
  ]

if.then:
  %cmp = icmp uge i32 %blksA, %nblks
  %frombool1 = zext i1 %cmp to i8
  br label %if.end

if.then2:
  %add = add i32 %nblks, %blksB
  %cmp2 = icmp ule i32 %add, %blksA
  %frombool3 = zext i1 %cmp2 to i8
  br label %if.end

if.then3:
  %add2 = add i32 %nblks, %blksA
  %cmp3 = icmp ule i32 %add2, %blksA
  %frombool4 = zext i1 %cmp3 to i8
  br label %if.end

if.end:
  %obeys.0 = phi i8 [ %frombool1, %if.then ], [ %frombool3, %if.then2 ], [ %frombool4, %if.then3 ]
  %tobool4 = icmp ne i8 %obeys.0, 0
  ret i1 %tobool4
}


define i32 @test_pr30188(i1 zeroext %flag, i32 %x) {
; CHECK-LABEL: @test_pr30188(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[Y:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[Z:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[Y_Z:%.*]] = select i1 [[FLAG:%.*]], ptr [[Y]], ptr [[Z]]
; CHECK-NEXT:    store i32 [[X:%.*]], ptr [[Y_Z]], align 4
; CHECK-NEXT:    ret i32 1
;
entry:
  %y = alloca i32
  %z = alloca i32
  br i1 %flag, label %if.then, label %if.else

if.then:
  store i32 %x, ptr %y
  br label %if.end

if.else:
  store i32 %x, ptr %z
  br label %if.end

if.end:
  ret i32 1
}


define i32 @test_pr30188a(i1 zeroext %flag, i32 %x) {
; CHECK-LABEL: @test_pr30188a(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[Y:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[Z:%.*]] = alloca i32, align 4
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[Z_SINK:%.*]] = phi ptr [ [[Y]], [[IF_THEN]] ], [ [[Z]], [[ENTRY:%.*]] ]
; CHECK-NEXT:    [[THREE:%.*]] = load i32, ptr [[Z_SINK]], align 4
; CHECK-NEXT:    [[FOUR:%.*]] = add i32 [[THREE]], 2
; CHECK-NEXT:    store i32 [[FOUR]], ptr [[Y]], align 4
; CHECK-NEXT:    ret i32 1
;
entry:
  %y = alloca i32
  %z = alloca i32
  br i1 %flag, label %if.then, label %if.else

if.then:
  call void @g()
  %one = load i32, ptr %y
  %two = add i32 %one, 2
  store i32 %two, ptr %y
  br label %if.end

if.else:
  %three = load i32, ptr %z
  %four = add i32 %three, 2
  store i32 %four, ptr %y
  br label %if.end

if.end:
  ret i32 1
}


; The phi is confusing - both add instructions are used by it, but
; not on their respective unconditional arcs. It should not be
; optimized.
define void @test_pr30292(i1 %cond, i1 %cond2, i32 %a, i32 %b) {
; CHECK-LABEL: @test_pr30292(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[ADD1:%.*]] = add i32 [[A:%.*]], 1
; CHECK-NEXT:    br label [[SUCC:%.*]]
; CHECK:       two:
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    [[ADD2:%.*]] = add i32 [[A]], 1
; CHECK-NEXT:    br label [[SUCC]]
; CHECK:       succ:
; CHECK-NEXT:    [[P:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[ADD1]], [[SUCC]] ], [ [[ADD2]], [[TWO:%.*]] ]
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[TWO]], label [[SUCC]]
;
entry:
  %add1 = add i32 %a, 1
  br label %succ

one:
  br i1 %cond, label %two, label %succ

two:
  call void @g()
  %add2 = add i32 %a, 1
  br label %succ

succ:
  %p = phi i32 [ 0, %entry ], [ %add1, %one ], [ %add2, %two ]
  br label %one
}
declare void @g()


define zeroext i1 @test_pr30244(i1 zeroext %flag, i1 zeroext %flag2, i32 %blksA, i32 %blksB, i32 %nblks) {
; CHECK-LABEL: @test_pr30244(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[P:%.*]] = alloca i8, align 1
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[BLKSA:%.*]], [[NBLKS:%.*]]
; CHECK-NEXT:    br label [[IF_END_SINK_SPLIT:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    br i1 [[FLAG2:%.*]], label [[IF_THEN2:%.*]], label [[IF_END:%.*]]
; CHECK:       if.then2:
; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[NBLKS]], [[BLKSB:%.*]]
; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i32 [[ADD]], [[BLKSA]]
; CHECK-NEXT:    br label [[IF_END_SINK_SPLIT]]
; CHECK:       if.end.sink.split:
; CHECK-NEXT:    [[CMP2_SINK:%.*]] = phi i1 [ [[CMP2]], [[IF_THEN2]] ], [ [[CMP]], [[IF_THEN]] ]
; CHECK-NEXT:    [[FROMBOOL3:%.*]] = zext i1 [[CMP2_SINK]] to i8
; CHECK-NEXT:    store i8 [[FROMBOOL3]], ptr [[P]], align 1
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    ret i1 true
;
entry:
  %p = alloca i8
  br i1 %flag, label %if.then, label %if.else

if.then:
  %cmp = icmp uge i32 %blksA, %nblks
  %frombool1 = zext i1 %cmp to i8
  store i8 %frombool1, ptr %p
  br label %if.end

if.else:
  br i1 %flag2, label %if.then2, label %if.end

if.then2:
  %add = add i32 %nblks, %blksB
  %cmp2 = icmp ule i32 %add, %blksA
  %frombool3 = zext i1 %cmp2 to i8
  store i8 %frombool3, ptr %p
  br label %if.end

if.end:
  ret i1 true
}


define i32 @test_pr30373a(i1 zeroext %flag, i32 %x, i32 %y) {
; CHECK-LABEL: @test_pr30373a(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[X_Y:%.*]] = select i1 [[FLAG:%.*]], i32 [[X:%.*]], i32 [[Y:%.*]]
; CHECK-NEXT:    [[X1:%.*]] = call i32 @foo(i32 [[X_Y]], i32 0) #[[ATTR0]]
; CHECK-NEXT:    [[Y1:%.*]] = call i32 @foo(i32 [[X_Y]], i32 1) #[[ATTR0]]
; CHECK-NEXT:    [[Z1:%.*]] = lshr i32 [[Y1]], 8
; CHECK-NEXT:    [[RET:%.*]] = add i32 [[X1]], [[Z1]]
; CHECK-NEXT:    ret i32 [[RET]]
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %x0 = call i32 @foo(i32 %x, i32 0) nounwind readnone
  %y0 = call i32 @foo(i32 %x, i32 1) nounwind readnone
  %z0 = lshr i32 %y0, 8
  br label %if.end

if.else:
  %x1 = call i32 @foo(i32 %y, i32 0) nounwind readnone
  %y1 = call i32 @foo(i32 %y, i32 1) nounwind readnone
  %z1 = lshr exact i32 %y1, 8
  br label %if.end

if.end:
  %xx = phi i32 [ %x0, %if.then ], [ %x1, %if.else ]
  %yy = phi i32 [ %z0, %if.then ], [ %z1, %if.else ]
  %ret = add i32 %xx, %yy
  ret i32 %ret
}


define i32 @test_pr30373b(i1 zeroext %flag, i32 %x, i32 %y) {
; CHECK-LABEL: @test_pr30373b(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[X_Y:%.*]] = select i1 [[FLAG:%.*]], i32 [[X:%.*]], i32 [[Y:%.*]]
; CHECK-NEXT:    [[X1:%.*]] = call i32 @foo(i32 [[X_Y]], i32 0) #[[ATTR0]]
; CHECK-NEXT:    [[Y1:%.*]] = call i32 @foo(i32 [[X_Y]], i32 1) #[[ATTR0]]
; CHECK-NEXT:    [[Z1:%.*]] = lshr i32 [[Y1]], 8
; CHECK-NEXT:    [[RET:%.*]] = add i32 [[X1]], [[Z1]]
; CHECK-NEXT:    ret i32 [[RET]]
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %x0 = call i32 @foo(i32 %x, i32 0) nounwind readnone
  %y0 = call i32 @foo(i32 %x, i32 1) nounwind readnone
  %z0 = lshr exact i32 %y0, 8
  br label %if.end

if.else:
  %x1 = call i32 @foo(i32 %y, i32 0) nounwind readnone
  %y1 = call i32 @foo(i32 %y, i32 1) nounwind readnone
  %z1 = lshr i32 %y1, 8
  br label %if.end

if.end:
  %xx = phi i32 [ %x0, %if.then ], [ %x1, %if.else ]
  %yy = phi i32 [ %z0, %if.then ], [ %z1, %if.else ]
  %ret = add i32 %xx, %yy
  ret i32 %ret
}



; FIXME:  Should turn into select
define float @allow_intrinsic_remove_constant(i1 zeroext %flag, float %w, float %x, float %y) {
; CHECK-LABEL: @allow_intrinsic_remove_constant(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[DUMMY:%.*]] = fadd float [[W:%.*]], 4.000000e+00
; CHECK-NEXT:    [[SV1:%.*]] = call float @llvm.fma.f32(float [[DUMMY]], float 2.000000e+00, float 1.000000e+00)
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    [[DUMMY1:%.*]] = fadd float [[W]], 8.000000e+00
; CHECK-NEXT:    [[SV2:%.*]] = call float @llvm.fma.f32(float 2.000000e+00, float [[DUMMY1]], float 1.000000e+00)
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[P:%.*]] = phi float [ [[SV1]], [[IF_THEN]] ], [ [[SV2]], [[IF_ELSE]] ]
; CHECK-NEXT:    ret float [[P]]
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %dummy = fadd float %w, 4.0
  %sv1 = call float @llvm.fma.f32(float %dummy, float 2.0, float 1.0)
  br label %if.end

if.else:
  %dummy1 = fadd float %w, 8.0
  %sv2 = call float @llvm.fma.f32(float 2.0, float %dummy1, float 1.0)
  br label %if.end

if.end:
  %p = phi float [ %sv1, %if.then ], [ %sv2, %if.else ]
  ret float %p
}

declare float @llvm.fma.f32(float, float, float)

define i32 @no_remove_constant_immarg(i1 zeroext %flag, i32 %w, i32 %x, i32 %y) {
; CHECK-LABEL: @no_remove_constant_immarg(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[DUMMY:%.*]] = add i32 [[W:%.*]], 5
; CHECK-NEXT:    [[SV1:%.*]] = call i32 @llvm.ctlz.i32(i32 [[X:%.*]], i1 true)
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    [[DUMMY1:%.*]] = add i32 [[W]], 6
; CHECK-NEXT:    [[SV2:%.*]] = call i32 @llvm.ctlz.i32(i32 [[X]], i1 false)
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[P:%.*]] = phi i32 [ [[SV1]], [[IF_THEN]] ], [ [[SV2]], [[IF_ELSE]] ]
; CHECK-NEXT:    ret i32 1
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %dummy = add i32 %w, 5
  %sv1 = call i32 @llvm.ctlz.i32(i32 %x, i1 true)
  br label %if.end

if.else:
  %dummy1 = add i32 %w, 6
  %sv2 = call i32 @llvm.ctlz.i32(i32 %x, i1 false)
  br label %if.end

if.end:
  %p = phi i32 [ %sv1, %if.then ], [ %sv2, %if.else ]
  ret i32 1
}

declare void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) nocapture, ptr addrspace(1) nocapture readonly, i64, i1)

; Make sure a memcpy size isn't replaced with a variable
define void @no_replace_memcpy_size(i1 zeroext %flag, ptr addrspace(1) %dst, ptr addrspace(1) %src) {
; CHECK-LABEL: @no_replace_memcpy_size(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) [[DST:%.*]], ptr addrspace(1) [[SRC:%.*]], i64 1024, i1 false)
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) [[DST]], ptr addrspace(1) [[SRC]], i64 4096, i1 false)
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    ret void
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dst, ptr addrspace(1) %src, i64 1024, i1 false)
  br label %if.end

if.else:
  call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dst, ptr addrspace(1) %src, i64 4096, i1 false)
  br label %if.end

if.end:
  ret void
}

declare void @llvm.memmove.p1.p1.i64(ptr addrspace(1) nocapture, ptr addrspace(1) nocapture readonly, i64, i1)

; Make sure a memmove size isn't replaced with a variable
define void @no_replace_memmove_size(i1 zeroext %flag, ptr addrspace(1) %dst, ptr addrspace(1) %src) {
; CHECK-LABEL: @no_replace_memmove_size(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    call void @llvm.memmove.p1.p1.i64(ptr addrspace(1) [[DST:%.*]], ptr addrspace(1) [[SRC:%.*]], i64 1024, i1 false)
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    call void @llvm.memmove.p1.p1.i64(ptr addrspace(1) [[DST]], ptr addrspace(1) [[SRC]], i64 4096, i1 false)
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    ret void
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  call void @llvm.memmove.p1.p1.i64(ptr addrspace(1) %dst, ptr addrspace(1) %src, i64 1024, i1 false)
  br label %if.end

if.else:
  call void @llvm.memmove.p1.p1.i64(ptr addrspace(1) %dst, ptr addrspace(1) %src, i64 4096, i1 false)
  br label %if.end

if.end:
  ret void
}

declare void @llvm.memset.p1.i64(ptr addrspace(1) nocapture, i8, i64, i1)

; Make sure a memset size isn't replaced with a variable
define void @no_replace_memset_size(i1 zeroext %flag, ptr addrspace(1) %dst) {
; CHECK-LABEL: @no_replace_memset_size(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    call void @llvm.memset.p1.i64(ptr addrspace(1) [[DST:%.*]], i8 0, i64 1024, i1 false)
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    call void @llvm.memset.p1.i64(ptr addrspace(1) [[DST]], i8 0, i64 4096, i1 false)
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    ret void
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  call void @llvm.memset.p1.i64(ptr addrspace(1) %dst, i8 0, i64 1024, i1 false)
  br label %if.end

if.else:
  call void @llvm.memset.p1.i64(ptr addrspace(1) %dst, i8 0, i64 4096, i1 false)
  br label %if.end

if.end:
  ret void
}

; Check that simplifycfg doesn't sink and merge inline-asm instructions.

define i32 @test_inline_asm1(i32 %c, i32 %r6) {
; CHECK-LABEL: @test_inline_asm1(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i32 [[C:%.*]], 0
; CHECK-NEXT:    br i1 [[TOBOOL]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[TMP0:%.*]] = call i32 asm "rorl $2, $0", "=&r,0,n,~{dirflag},~{fpsr},~{flags}"(i32 [[R6:%.*]], i32 8)
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    [[TMP1:%.*]] = call i32 asm "rorl $2, $0", "=&r,0,n,~{dirflag},~{fpsr},~{flags}"(i32 [[R6]], i32 6)
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    [[R6_ADDR_0:%.*]] = phi i32 [ [[TMP0]], [[IF_THEN]] ], [ [[TMP1]], [[IF_ELSE]] ]
; CHECK-NEXT:    ret i32 [[R6_ADDR_0]]
;
entry:
  %tobool = icmp eq i32 %c, 0
  br i1 %tobool, label %if.else, label %if.then

if.then:
  %0 = call i32 asm "rorl $2, $0", "=&r,0,n,~{dirflag},~{fpsr},~{flags}"(i32 %r6, i32 8)
  br label %if.end

if.else:
  %1 = call i32 asm "rorl $2, $0", "=&r,0,n,~{dirflag},~{fpsr},~{flags}"(i32 %r6, i32 6)
  br label %if.end

if.end:
  %r6.addr.0 = phi i32 [ %0, %if.then ], [ %1, %if.else ]
  ret i32 %r6.addr.0
}


declare i32 @call_target()

define void @test_operand_bundles(i1 %cond, ptr %ptr) {
; CHECK-LABEL: @test_operand_bundles(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
; CHECK:       left:
; CHECK-NEXT:    [[VAL0:%.*]] = call i32 @call_target() [ "deopt"(i32 10) ]
; CHECK-NEXT:    br label [[MERGE:%.*]]
; CHECK:       right:
; CHECK-NEXT:    [[VAL1:%.*]] = call i32 @call_target() [ "deopt"(i32 20) ]
; CHECK-NEXT:    br label [[MERGE]]
; CHECK:       merge:
; CHECK-NEXT:    [[VAL1_SINK:%.*]] = phi i32 [ [[VAL1]], [[RIGHT]] ], [ [[VAL0]], [[LEFT]] ]
; CHECK-NEXT:    store i32 [[VAL1_SINK]], ptr [[PTR:%.*]], align 4
; CHECK-NEXT:    ret void
;
entry:
  br i1 %cond, label %left, label %right

left:
  %val0 = call i32 @call_target() [ "deopt"(i32 10) ]
  store i32 %val0, ptr %ptr
  br label %merge

right:
  %val1 = call i32 @call_target() [ "deopt"(i32 20) ]
  store i32 %val1, ptr %ptr
  br label %merge

merge:
  ret void
}


%TP = type {i32, i32}

define i32 @test_insertvalue(i1 zeroext %flag, %TP %P) {
; CHECK-LABEL: @test_insertvalue(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[DOT:%.*]] = select i1 [[FLAG:%.*]], i32 0, i32 1
; CHECK-NEXT:    [[I2:%.*]] = insertvalue [[TP:%.*]] [[P:%.*]], i32 [[DOT]], 0
; CHECK-NEXT:    ret i32 1
;
entry:
  br i1 %flag, label %if.then, label %if.else

if.then:
  %i1 = insertvalue %TP %P, i32 0, 0
  br label %if.end

if.else:
  %i2 = insertvalue %TP %P, i32 1, 0
  br label %if.end

if.end:
  %i = phi %TP [%i1, %if.then], [%i2, %if.else]
  ret i32 1
}



declare void @baz(i32)

define void @test_sink_void_calls(i32 %x) {
; CHECK-LABEL: @test_sink_void_calls(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    switch i32 [[X:%.*]], label [[DEFAULT:%.*]] [
; CHECK-NEXT:      i32 0, label [[RETURN:%.*]]
; CHECK-NEXT:      i32 1, label [[BB1:%.*]]
; CHECK-NEXT:      i32 2, label [[BB2:%.*]]
; CHECK-NEXT:      i32 3, label [[BB3:%.*]]
; CHECK-NEXT:      i32 4, label [[BB4:%.*]]
; CHECK-NEXT:    ]
; CHECK:       bb1:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       bb2:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       bb3:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       bb4:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       default:
; CHECK-NEXT:    unreachable
; CHECK:       return:
; CHECK-NEXT:    [[DOTSINK:%.*]] = phi i32 [ 90, [[BB4]] ], [ 78, [[BB3]] ], [ 56, [[BB2]] ], [ 34, [[BB1]] ], [ 12, [[ENTRY:%.*]] ]
; CHECK-NEXT:    call void @baz(i32 [[DOTSINK]])
; CHECK-NEXT:    ret void
;
entry:
  switch i32 %x, label %default [
  i32 0, label %bb0
  i32 1, label %bb1
  i32 2, label %bb2
  i32 3, label %bb3
  i32 4, label %bb4
  ]
bb0:
  call void @baz(i32 12)
  br label %return
bb1:
  call void @baz(i32 34)
  br label %return
bb2:
  call void @baz(i32 56)
  br label %return
bb3:
  call void @baz(i32 78)
  br label %return
bb4:
  call void @baz(i32 90)
  br label %return
default:
  unreachable
return:
  ret void

; Check that the calls get sunk to the return block.
; We would previously not sink calls without uses, see PR41259.
}

define i32 @test_not_sink_lifetime_marker(i1 zeroext %flag, i32 %x) {
; CHECK-LABEL: @test_not_sink_lifetime_marker(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[Y:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[Z:%.*]] = alloca i32, align 4
; CHECK-NEXT:    br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 4, ptr [[Y]])
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.else:
; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 4, ptr [[Z]])
; CHECK-NEXT:    br label [[IF_END]]
; CHECK:       if.end:
; CHECK-NEXT:    ret i32 1
;
entry:
  %y = alloca i32
  %z = alloca i32
  br i1 %flag, label %if.then, label %if.else

if.then:
  call void @llvm.lifetime.end.p0(i64 4, ptr %y)
  br label %if.end

if.else:
  call void @llvm.lifetime.end.p0(i64 4, ptr %z)
  br label %if.end

if.end:
  ret i32 1
}

define void @direct_caller(i1 %c) {
; CHECK-LABEL: @direct_caller(
; CHECK-NEXT:    br i1 [[C:%.*]], label [[CALL_FOO:%.*]], label [[CALL_BAR:%.*]]
; CHECK:       call_foo:
; CHECK-NEXT:    call void @direct_callee()
; CHECK-NEXT:    br label [[END:%.*]]
; CHECK:       call_bar:
; CHECK-NEXT:    call void @direct_callee2()
; CHECK-NEXT:    br label [[END]]
; CHECK:       end:
; CHECK-NEXT:    ret void
;
  br i1 %c, label %call_foo, label %call_bar

call_foo:
  call void @direct_callee()
  br label %end

call_bar:
  call void @direct_callee2()
  br label %end

end:
  ret void
}

define void @indirect_caller(i1 %c, i32 %v, ptr %foo, ptr %bar) {
; CHECK-LABEL: @indirect_caller(
; CHECK-NEXT:  end:
; CHECK-NEXT:    [[FOO_BAR:%.*]] = select i1 [[C:%.*]], ptr [[FOO:%.*]], ptr [[BAR:%.*]]
; CHECK-NEXT:    tail call void [[FOO_BAR]](i32 [[V:%.*]])
; CHECK-NEXT:    ret void
;
  br i1 %c, label %call_foo, label %call_bar

call_foo:
  tail call void %foo(i32 %v)
  br label %end

call_bar:
  tail call void %bar(i32 %v)
  br label %end

end:
  ret void
}

define void @maybe_indirect_caller(ptr %fun) {
; CHECK-LABEL: @maybe_indirect_caller(
; CHECK-NEXT:    [[C:%.*]] = icmp eq ptr [[FUN:%.*]], @direct_callee
; CHECK-NEXT:    br i1 [[C]], label [[IF_TRUE_DIRECT_TARG:%.*]], label [[IF_FALSE_ORIG_INDIRECT:%.*]]
; CHECK:       if.true.direct_targ:
; CHECK-NEXT:    tail call void @direct_callee()
; CHECK-NEXT:    br label [[IF_END_ICP:%.*]]
; CHECK:       if.false.orig_indirect:
; CHECK-NEXT:    tail call void [[FUN]]()
; CHECK-NEXT:    br label [[IF_END_ICP]]
; CHECK:       if.end.icp:
; CHECK-NEXT:    ret void
;
  %c = icmp eq ptr %fun, @direct_callee
  br i1 %c, label %if.true.direct_targ, label %if.false.orig_indirect

if.true.direct_targ:
  tail call void @direct_callee()
  br label %if.end.icp

if.false.orig_indirect:
  tail call void %fun()
  br label %if.end.icp

if.end.icp:
  ret void
}
define void @maybe_indirect_caller2(ptr %fun) {
; CHECK-LABEL: @maybe_indirect_caller2(
; CHECK-NEXT:    [[C:%.*]] = icmp eq ptr [[FUN:%.*]], @direct_callee
; CHECK-NEXT:    br i1 [[C]], label [[IF_TRUE_DIRECT_TARG:%.*]], label [[IF_FALSE_ORIG_INDIRECT:%.*]]
; CHECK:       if.false.orig_indirect:
; CHECK-NEXT:    tail call void [[FUN]]()
; CHECK-NEXT:    br label [[IF_END_ICP:%.*]]
; CHECK:       if.true.direct_targ:
; CHECK-NEXT:    tail call void @direct_callee()
; CHECK-NEXT:    br label [[IF_END_ICP]]
; CHECK:       if.end.icp:
; CHECK-NEXT:    ret void
;
  %c = icmp eq ptr %fun, @direct_callee
  br i1 %c, label %if.true.direct_targ, label %if.false.orig_indirect

if.false.orig_indirect:
  tail call void %fun()
  br label %if.end.icp

if.true.direct_targ:
  tail call void @direct_callee()
  br label %if.end.icp

if.end.icp:
  ret void
}
declare void @direct_callee()
declare void @direct_callee2()
declare void @direct_callee3()

declare void @llvm.lifetime.start.p0(i64, ptr nocapture)
declare void @llvm.lifetime.end.p0(i64, ptr nocapture)

define void @creating_too_many_phis(i1 %cond, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h) {
; CHECK-LABEL: @creating_too_many_phis(
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[BB0:%.*]], label [[BB1:%.*]]
; CHECK:       bb0:
; CHECK-NEXT:    [[V0:%.*]] = add i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[V1:%.*]] = add i32 [[V0]], [[C:%.*]]
; CHECK-NEXT:    [[V2:%.*]] = add i32 [[D:%.*]], [[E:%.*]]
; CHECK-NEXT:    [[R3:%.*]] = add i32 [[V1]], [[V2]]
; CHECK-NEXT:    br label [[END:%.*]]
; CHECK:       bb1:
; CHECK-NEXT:    [[V4:%.*]] = add i32 [[A]], [[B]]
; CHECK-NEXT:    [[V5:%.*]] = add i32 [[V4]], [[C]]
; CHECK-NEXT:    [[V6:%.*]] = add i32 [[G:%.*]], [[H:%.*]]
; CHECK-NEXT:    [[R7:%.*]] = add i32 [[V5]], [[V6]]
; CHECK-NEXT:    br label [[END]]
; CHECK:       end:
; CHECK-NEXT:    [[R7_SINK:%.*]] = phi i32 [ [[R7]], [[BB1]] ], [ [[R3]], [[BB0]] ]
; CHECK-NEXT:    call void @use32(i32 [[R7_SINK]])
; CHECK-NEXT:    ret void
;
  br i1 %cond, label %bb0, label %bb1

bb0:
  %v0 = add i32 %a, %b
  %v1 = add i32 %v0, %c
  %v2 = add i32 %d, %e
  %r3 = add i32 %v1, %v2
  call void @use32(i32 %r3)
  br label %end

bb1:
  %v4 = add i32 %a, %b
  %v5 = add i32 %v4, %c
  %v6 = add i32 %g, %h
  %r7 = add i32 %v5, %v6
  call void @use32(i32 %r7)
  br label %end

end:
  ret void
}
declare void @use32(i32)

define void @multiple_cond_preds(i1 %c0, i1 %c1, i1 %c2) {
; CHECK-LABEL: @multiple_cond_preds(
; CHECK-NEXT:  dispatch0:
; CHECK-NEXT:    br i1 [[C0:%.*]], label [[DISPATCH1:%.*]], label [[DISPATCH2:%.*]]
; CHECK:       dispatch1:
; CHECK-NEXT:    call void @direct_callee2()
; CHECK-NEXT:    br i1 [[C1:%.*]], label [[END_SINK_SPLIT:%.*]], label [[END:%.*]]
; CHECK:       dispatch2:
; CHECK-NEXT:    call void @direct_callee3()
; CHECK-NEXT:    br i1 [[C2:%.*]], label [[END_SINK_SPLIT]], label [[END]]
; CHECK:       end.sink.split:
; CHECK-NEXT:    call void @direct_callee()
; CHECK-NEXT:    br label [[END]]
; CHECK:       end:
; CHECK-NEXT:    ret void
;
dispatch0:
  br i1 %c0, label %dispatch1, label %dispatch2

dispatch1:
  call void @direct_callee2()
  br i1 %c1, label %uncond_pred0, label %end

dispatch2:
  call void @direct_callee3()
  br i1 %c2, label %uncond_pred1, label %end

uncond_pred0:
  call void @direct_callee()
  br label %end

uncond_pred1:
  call void @direct_callee()
  br label %end

end:
  ret void
}

define void @nontemporal(ptr %ptr, i1 %cond) {
; CHECK-LABEL: @nontemporal(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    store i64 0, ptr [[PTR:%.*]], align 8, !nontemporal [[META7:![0-9]+]]
; CHECK-NEXT:    ret void
;
entry:
  br i1 %cond, label %if.then, label %if.else

if.then:
  store i64 0, ptr %ptr, align 8, !nontemporal !12
  br label %if.end

if.else:
  store i64 0, ptr %ptr, align 8, !nontemporal !12
  br label %if.end

if.end:
  ret void
}

define void @nontemporal_mismatch(ptr %ptr, i1 %cond) {
; CHECK-LABEL: @nontemporal_mismatch(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    store i64 0, ptr [[PTR:%.*]], align 8
; CHECK-NEXT:    ret void
;
entry:
  br i1 %cond, label %if.then, label %if.else

if.then:
  store i64 0, ptr %ptr, align 8, !nontemporal !12
  br label %if.end

if.else:
  store i64 0, ptr %ptr, align 8
  br label %if.end

if.end:
  ret void
}

define void @loop_use_in_different_bb(i32 %n) {
; CHECK-LABEL: @loop_use_in_different_bb(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[N:%.*]], 1
; CHECK-NEXT:    br label [[FOR_COND:%.*]]
; CHECK:       for.cond:
; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY:%.*]] ]
; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i32 [[IV]], [[ADD]]
; CHECK-NEXT:    br i1 [[EXITCOND]], label [[RETURN:%.*]], label [[FOR_BODY]]
; CHECK:       for.body:
; CHECK-NEXT:    [[INC]] = add i32 [[IV]], 1
; CHECK-NEXT:    br label [[FOR_COND]]
; CHECK:       return:
; CHECK-NEXT:    ret void
;
entry:
  %add = add i32 %n, 1
  br label %for.cond

for.cond:
  %iv = phi i32 [ 0, %entry ], [ %inc, %for.body ]
  %exitcond = icmp eq i32 %iv, %add
  br i1 %exitcond, label %return, label %for.body

for.body:
  %inc = add i32 %iv, 1
  br label %for.cond

return:
  ret void
}

define void @loop_use_in_different_bb_phi(i32 %n) {
; CHECK-LABEL: @loop_use_in_different_bb_phi(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[N:%.*]], 1
; CHECK-NEXT:    br label [[FOR_COND:%.*]]
; CHECK:       for.cond:
; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY:%.*]] ]
; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i32 [[IV]], 42
; CHECK-NEXT:    br i1 [[EXITCOND]], label [[RETURN:%.*]], label [[FOR_BODY]]
; CHECK:       for.body:
; CHECK-NEXT:    [[DUMMY:%.*]] = phi i32 [ [[ADD]], [[FOR_COND]] ]
; CHECK-NEXT:    [[INC]] = add i32 [[IV]], 1
; CHECK-NEXT:    br label [[FOR_COND]]
; CHECK:       return:
; CHECK-NEXT:    ret void
;
entry:
  %add = add i32 %n, 1
  br label %for.cond

for.cond:
  %iv = phi i32 [ 0, %entry ], [ %inc, %for.body ]
  %exitcond = icmp eq i32 %iv, 42
  br i1 %exitcond, label %return, label %for.body

for.body:
  %dummy = phi i32 [ %add, %for.cond ]
  %inc = add i32 %iv, 1
  br label %for.cond

return:
  ret void
}

define void @loop_use_in_wrong_phi_operand(i32 %n) {
; CHECK-LABEL: @loop_use_in_wrong_phi_operand(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[N:%.*]], 1
; CHECK-NEXT:    br label [[FOR_COND:%.*]]
; CHECK:       for.cond:
; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[ADD]], [[FOR_BODY:%.*]] ]
; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i32 [[IV]], 42
; CHECK-NEXT:    br i1 [[EXITCOND]], label [[RETURN:%.*]], label [[FOR_BODY]]
; CHECK:       for.body:
; CHECK-NEXT:    [[INC:%.*]] = add i32 [[IV]], 1
; CHECK-NEXT:    br label [[FOR_COND]]
; CHECK:       return:
; CHECK-NEXT:    ret void
;
entry:
  %add = add i32 %n, 1
  br label %for.cond

for.cond:
  %iv = phi i32 [ 0, %entry ], [ %add, %for.body ]
  %exitcond = icmp eq i32 %iv, 42
  br i1 %exitcond, label %return, label %for.body

for.body:
  %inc = add i32 %iv, 1
  br label %for.cond

return:
  ret void
}

define ptr @multi_use_in_phi(i1 %cond, ptr %p, i64 %a, i64 %b) {
; CHECK-LABEL: @multi_use_in_phi(
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF:%.*]], label [[JOIN:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @dummy()
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[GEP1_B:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[A:%.*]]
; CHECK-NEXT:    [[GEP2_B:%.*]] = getelementptr i8, ptr [[GEP1_B]], i64 [[B:%.*]]
; CHECK-NEXT:    call void @use.ptr(ptr [[GEP1_B]])
; CHECK-NEXT:    ret ptr [[GEP2_B]]
;
  br i1 %cond, label %if, label %else

if:
  call void @dummy()
  %gep1.a = getelementptr i8, ptr %p, i64 %a
  %gep2.a = getelementptr i8, ptr %gep1.a, i64 %b
  br label %join

else:
  %gep1.b = getelementptr i8, ptr %p, i64 %a
  %gep2.b = getelementptr i8, ptr %gep1.b, i64 %b
  br label %join

join:
  %phi1 = phi ptr [ %gep1.a, %if ], [ %gep1.b, %else ]
  %phi2 = phi ptr [ %gep2.a, %if ], [ %gep2.b, %else ]
  call void @use.ptr(ptr %phi1)
  ret ptr %phi2
}

define ptr @multi_use_in_phi_inconsistent(i1 %cond, ptr %p, i64 %a, i64 %b) {
; CHECK-LABEL: @multi_use_in_phi_inconsistent(
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @dummy()
; CHECK-NEXT:    [[GEP1_A:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[A:%.*]]
; CHECK-NEXT:    br label [[JOIN:%.*]]
; CHECK:       else:
; CHECK-NEXT:    [[GEP1_B:%.*]] = getelementptr i8, ptr [[P]], i64 [[A]]
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[GEP1_B_SINK:%.*]] = phi ptr [ [[GEP1_B]], [[ELSE]] ], [ [[GEP1_A]], [[IF]] ]
; CHECK-NEXT:    [[PHI1:%.*]] = phi ptr [ [[GEP1_A]], [[IF]] ], [ [[P]], [[ELSE]] ]
; CHECK-NEXT:    [[GEP2_B:%.*]] = getelementptr i8, ptr [[GEP1_B_SINK]], i64 [[B:%.*]]
; CHECK-NEXT:    call void @use.ptr(ptr [[PHI1]])
; CHECK-NEXT:    ret ptr [[GEP2_B]]
;
  br i1 %cond, label %if, label %else

if:
  call void @dummy()
  %gep1.a = getelementptr i8, ptr %p, i64 %a
  %gep2.a = getelementptr i8, ptr %gep1.a, i64 %b
  br label %join

else:
  %gep1.b = getelementptr i8, ptr %p, i64 %a
  %gep2.b = getelementptr i8, ptr %gep1.b, i64 %b
  br label %join

join:
  %phi1 = phi ptr [ %gep1.a, %if ], [ %p, %else ]
  %phi2 = phi ptr [ %gep2.a, %if ], [ %gep2.b, %else ]
  call void @use.ptr(ptr %phi1)
  ret ptr %phi2
}

define i64 @multi_use_in_block(i1 %cond, ptr %p, i64 %a, i64 %b) {
; CHECK-LABEL: @multi_use_in_block(
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF:%.*]], label [[JOIN:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @dummy()
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[GEP1_B:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[A:%.*]]
; CHECK-NEXT:    [[V_B:%.*]] = load i64, ptr [[GEP1_B]], align 8
; CHECK-NEXT:    [[GEP2_B:%.*]] = getelementptr i8, ptr [[GEP1_B]], i64 [[V_B]]
; CHECK-NEXT:    call void @use.ptr(ptr [[GEP2_B]])
; CHECK-NEXT:    ret i64 [[V_B]]
;
  br i1 %cond, label %if, label %else

if:
  call void @dummy()
  %gep1.a = getelementptr i8, ptr %p, i64 %a
  %v.a = load i64, ptr %gep1.a
  %gep2.a = getelementptr i8, ptr %gep1.a, i64 %v.a
  br label %join

else:
  %gep1.b = getelementptr i8, ptr %p, i64 %a
  %v.b = load i64, ptr %gep1.b
  %gep2.b = getelementptr i8, ptr %gep1.b, i64 %v.b
  br label %join

join:
  %phi1 = phi i64 [ %v.a, %if ], [ %v.b, %else ]
  %phi2 = phi ptr [ %gep2.a, %if ], [ %gep2.b, %else ]
  call void @use.ptr(ptr %phi2)
  ret i64 %phi1
}

define i64 @multi_use_in_block_inconsistent(i1 %cond, ptr %p, i64 %a, i64 %b) {
; CHECK-LABEL: @multi_use_in_block_inconsistent(
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @dummy()
; CHECK-NEXT:    [[GEP1_A:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[A:%.*]]
; CHECK-NEXT:    [[V_A:%.*]] = load i64, ptr [[GEP1_A]], align 8
; CHECK-NEXT:    [[GEP2_A:%.*]] = getelementptr i8, ptr [[GEP1_A]], i64 [[V_A]]
; CHECK-NEXT:    br label [[JOIN:%.*]]
; CHECK:       else:
; CHECK-NEXT:    [[GEP1_B:%.*]] = getelementptr i8, ptr [[P]], i64 [[A]]
; CHECK-NEXT:    [[V_B:%.*]] = load i64, ptr [[P]], align 8
; CHECK-NEXT:    [[GEP2_B:%.*]] = getelementptr i8, ptr [[GEP1_B]], i64 [[V_B]]
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[PHI1:%.*]] = phi i64 [ [[V_A]], [[IF]] ], [ [[V_B]], [[ELSE]] ]
; CHECK-NEXT:    [[PHI2:%.*]] = phi ptr [ [[GEP2_A]], [[IF]] ], [ [[GEP2_B]], [[ELSE]] ]
; CHECK-NEXT:    call void @use.ptr(ptr [[PHI2]])
; CHECK-NEXT:    ret i64 [[PHI1]]
;
  br i1 %cond, label %if, label %else

if:
  call void @dummy()
  %gep1.a = getelementptr i8, ptr %p, i64 %a
  %v.a = load i64, ptr %gep1.a
  %gep2.a = getelementptr i8, ptr %gep1.a, i64 %v.a
  br label %join

else:
  %gep1.b = getelementptr i8, ptr %p, i64 %a
  %v.b = load i64, ptr %p
  %gep2.b = getelementptr i8, ptr %gep1.b, i64 %v.b
  br label %join

join:
  %phi1 = phi i64 [ %v.a, %if ], [ %v.b, %else ]
  %phi2 = phi ptr [ %gep2.a, %if ], [ %gep2.b, %else ]
  call void @use.ptr(ptr %phi2)
  ret i64 %phi1
}

define i64 @load_with_sunk_gep(i1 %cond, ptr %p, i64 %a, i64 %b) {
; CHECK-LABEL: @load_with_sunk_gep(
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF:%.*]], label [[JOIN:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @dummy()
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[B_SINK:%.*]] = phi i64 [ [[A:%.*]], [[IF]] ], [ [[B:%.*]], [[TMP0:%.*]] ]
; CHECK-NEXT:    [[GEP_B:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[B_SINK]]
; CHECK-NEXT:    [[V_B:%.*]] = load i64, ptr [[GEP_B]], align 8
; CHECK-NEXT:    ret i64 [[V_B]]
;
  br i1 %cond, label %if, label %else

if:
  call void @dummy()
  %gep.a = getelementptr i8, ptr %p, i64 %a
  %v.a = load i64, ptr %gep.a
  br label %join

else:
  %gep.b = getelementptr i8, ptr %p, i64 %b
  %v.b = load i64, ptr %gep.b
  br label %join

join:
  %v = phi i64 [ %v.a, %if ], [ %v.b, %else ]
  ret i64 %v
}

define i64 @load_with_non_sunk_gep_both(i1 %cond, ptr %p.a, ptr %p.b, i64 %a, i64 %b) {
; CHECK-LABEL: @load_with_non_sunk_gep_both(
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @dummy()
; CHECK-NEXT:    [[GEP_A:%.*]] = getelementptr i8, ptr [[P_A:%.*]], i64 [[A:%.*]]
; CHECK-NEXT:    [[V_A:%.*]] = load i64, ptr [[GEP_A]], align 8
; CHECK-NEXT:    br label [[JOIN:%.*]]
; CHECK:       else:
; CHECK-NEXT:    [[GEP_B:%.*]] = getelementptr i8, ptr [[P_B:%.*]], i64 [[B:%.*]]
; CHECK-NEXT:    [[V_B:%.*]] = load i64, ptr [[GEP_B]], align 8
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[V:%.*]] = phi i64 [ [[V_A]], [[IF]] ], [ [[V_B]], [[ELSE]] ]
; CHECK-NEXT:    ret i64 [[V]]
;
  br i1 %cond, label %if, label %else

if:
  call void @dummy()
  %gep.a = getelementptr i8, ptr %p.a, i64 %a
  %v.a = load i64, ptr %gep.a
  br label %join

else:
  %gep.b = getelementptr i8, ptr %p.b, i64 %b
  %v.b = load i64, ptr %gep.b
  br label %join

join:
  %v = phi i64 [ %v.a, %if ], [ %v.b, %else ]
  ret i64 %v
}

define i64 @load_with_non_sunk_gep_left(i1 %cond, ptr %p.a, ptr %p.b, i64 %b) {
; CHECK-LABEL: @load_with_non_sunk_gep_left(
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @dummy()
; CHECK-NEXT:    [[V_A:%.*]] = load i64, ptr [[P_A:%.*]], align 8
; CHECK-NEXT:    br label [[JOIN:%.*]]
; CHECK:       else:
; CHECK-NEXT:    [[GEP_B:%.*]] = getelementptr i8, ptr [[P_B:%.*]], i64 [[B:%.*]]
; CHECK-NEXT:    [[V_B:%.*]] = load i64, ptr [[GEP_B]], align 8
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[V:%.*]] = phi i64 [ [[V_A]], [[IF]] ], [ [[V_B]], [[ELSE]] ]
; CHECK-NEXT:    ret i64 [[V]]
;
  br i1 %cond, label %if, label %else

if:
  call void @dummy()
  %v.a = load i64, ptr %p.a
  br label %join

else:
  %gep.b = getelementptr i8, ptr %p.b, i64 %b
  %v.b = load i64, ptr %gep.b
  br label %join

join:
  %v = phi i64 [ %v.a, %if ], [ %v.b, %else ]
  ret i64 %v
}

define i64 @load_with_non_sunk_gep_right(i1 %cond, ptr %p.a, ptr %p.b, i64 %a) {
; CHECK-LABEL: @load_with_non_sunk_gep_right(
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @dummy()
; CHECK-NEXT:    [[GEP_A:%.*]] = getelementptr i8, ptr [[P_A:%.*]], i64 [[A:%.*]]
; CHECK-NEXT:    [[V_A:%.*]] = load i64, ptr [[GEP_A]], align 8
; CHECK-NEXT:    br label [[JOIN:%.*]]
; CHECK:       else:
; CHECK-NEXT:    [[V_B:%.*]] = load i64, ptr [[P_B:%.*]], align 8
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[V:%.*]] = phi i64 [ [[V_A]], [[IF]] ], [ [[V_B]], [[ELSE]] ]
; CHECK-NEXT:    ret i64 [[V]]
;
  br i1 %cond, label %if, label %else

if:
  call void @dummy()
  %gep.a = getelementptr i8, ptr %p.a, i64 %a
  %v.a = load i64, ptr %gep.a
  br label %join

else:
  %v.b = load i64, ptr %p.b
  br label %join

join:
  %v = phi i64 [ %v.a, %if ], [ %v.b, %else ]
  ret i64 %v
}

define void @store_with_non_sunk_gep(i1 %cond, ptr %p.a, ptr %p.b, i64 %a, i64 %b) {
; CHECK-LABEL: @store_with_non_sunk_gep(
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @dummy()
; CHECK-NEXT:    [[GEP_A:%.*]] = getelementptr i8, ptr [[P_A:%.*]], i64 [[A:%.*]]
; CHECK-NEXT:    store i64 0, ptr [[GEP_A]], align 8
; CHECK-NEXT:    br label [[JOIN:%.*]]
; CHECK:       else:
; CHECK-NEXT:    [[GEP_B:%.*]] = getelementptr i8, ptr [[P_B:%.*]], i64 [[B:%.*]]
; CHECK-NEXT:    store i64 0, ptr [[GEP_B]], align 8
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    ret void
;
  br i1 %cond, label %if, label %else

if:
  call void @dummy()
  %gep.a = getelementptr i8, ptr %p.a, i64 %a
  store i64 0, ptr %gep.a
  br label %join

else:
  %gep.b = getelementptr i8, ptr %p.b, i64 %b
  store i64 0, ptr %gep.b
  br label %join

join:
  ret void
}

define void @store_with_non_sunk_gep_as_value(i1 %cond, ptr %p, ptr %p.a, ptr %p.b, i64 %a, i64 %b) {
; CHECK-LABEL: @store_with_non_sunk_gep_as_value(
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @dummy()
; CHECK-NEXT:    [[GEP_A:%.*]] = getelementptr i8, ptr [[P_A:%.*]], i64 [[A:%.*]]
; CHECK-NEXT:    br label [[JOIN:%.*]]
; CHECK:       else:
; CHECK-NEXT:    [[GEP_B:%.*]] = getelementptr i8, ptr [[P_B:%.*]], i64 [[B:%.*]]
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[GEP_B_SINK:%.*]] = phi ptr [ [[GEP_B]], [[ELSE]] ], [ [[GEP_A]], [[IF]] ]
; CHECK-NEXT:    store ptr [[GEP_B_SINK]], ptr [[P:%.*]], align 8
; CHECK-NEXT:    ret void
;
  br i1 %cond, label %if, label %else

if:
  call void @dummy()
  %gep.a = getelementptr i8, ptr %p.a, i64 %a
  store ptr %gep.a, ptr %p
  br label %join

else:
  %gep.b = getelementptr i8, ptr %p.b, i64 %b
  store ptr %gep.b, ptr %p
  br label %join

join:
  ret void
}

define i32 @many_indirect_phis(i1 %cond, i32 %a, i32 %b) {
; CHECK-LABEL: @many_indirect_phis(
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF:%.*]], label [[JOIN:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @dummy()
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[B_SINK:%.*]] = phi i32 [ [[A:%.*]], [[IF]] ], [ [[B:%.*]], [[TMP0:%.*]] ]
; CHECK-NEXT:    [[DOTSINK3:%.*]] = phi i32 [ 10, [[IF]] ], [ 11, [[TMP0]] ]
; CHECK-NEXT:    [[DOTSINK2:%.*]] = phi i32 [ 20, [[IF]] ], [ 21, [[TMP0]] ]
; CHECK-NEXT:    [[DOTSINK1:%.*]] = phi i32 [ 30, [[IF]] ], [ 31, [[TMP0]] ]
; CHECK-NEXT:    [[DOTSINK:%.*]] = phi i32 [ 40, [[IF]] ], [ 41, [[TMP0]] ]
; CHECK-NEXT:    [[ADD_0_B:%.*]] = add i32 [[B_SINK]], 1
; CHECK-NEXT:    [[ADD_1_B:%.*]] = add i32 [[ADD_0_B]], [[DOTSINK3]]
; CHECK-NEXT:    [[ADD_2_B:%.*]] = add i32 [[ADD_1_B]], [[DOTSINK2]]
; CHECK-NEXT:    [[ADD_3_B:%.*]] = add i32 [[ADD_2_B]], [[DOTSINK1]]
; CHECK-NEXT:    [[ADD_4_B:%.*]] = add i32 [[ADD_3_B]], [[DOTSINK]]
; CHECK-NEXT:    ret i32 [[ADD_4_B]]
;
  br i1 %cond, label %if, label %else

if:
  call void @dummy()
  %add.0.a = add i32 %a, 1
  %add.1.a = add i32 %add.0.a, 10
  %add.2.a = add i32 %add.1.a, 20
  %add.3.a = add i32 %add.2.a, 30
  %add.4.a = add i32 %add.3.a, 40
  br label %join

else:
  %add.0.b = add i32 %b, 1
  %add.1.b = add i32 %add.0.b, 11
  %add.2.b = add i32 %add.1.b, 21
  %add.3.b = add i32 %add.2.b, 31
  %add.4.b = add i32 %add.3.b, 41
  br label %join

join:
  %phi = phi i32 [ %add.4.a, %if ], [ %add.4.b, %else ]
  ret i32 %phi
}

define i32 @store_and_unrelated_many_phi_add(i1 %cond, ptr %p, i32 %a, i32 %b) {
; CHECK-LABEL: @store_and_unrelated_many_phi_add(
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @dummy()
; CHECK-NEXT:    [[ADD_1:%.*]] = add i32 [[A:%.*]], 2
; CHECK-NEXT:    br label [[JOIN:%.*]]
; CHECK:       else:
; CHECK-NEXT:    [[ADD_2:%.*]] = add i32 [[B:%.*]], 3
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[ADD_1]], [[IF]] ], [ [[ADD_2]], [[ELSE]] ]
; CHECK-NEXT:    store i32 1, ptr [[P:%.*]], align 4
; CHECK-NEXT:    ret i32 [[PHI]]
;
  br i1 %cond, label %if, label %else

if:
  call void @dummy()
  %add.1 = add i32 %a, 2
  store i32 1, ptr %p
  br label %join

else:
  %add.2 = add i32 %b, 3
  store i32 1, ptr %p
  br label %join

join:
  %phi = phi i32 [ %add.1, %if ], [ %add.2, %else ]
  ret i32 %phi
}

define i32 @store_and_related_many_phi_add(i1 %cond, ptr %p, i32 %a, i32 %b) {
; CHECK-LABEL: @store_and_related_many_phi_add(
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @dummy()
; CHECK-NEXT:    [[ADD_1:%.*]] = add i32 [[A:%.*]], 2
; CHECK-NEXT:    br label [[JOIN:%.*]]
; CHECK:       else:
; CHECK-NEXT:    [[ADD_2:%.*]] = add i32 [[B:%.*]], 3
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[ADD_2_SINK:%.*]] = phi i32 [ [[ADD_2]], [[ELSE]] ], [ [[ADD_1]], [[IF]] ]
; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[ADD_1]], [[IF]] ], [ [[ADD_2]], [[ELSE]] ]
; CHECK-NEXT:    store i32 [[ADD_2_SINK]], ptr [[P:%.*]], align 4
; CHECK-NEXT:    ret i32 [[PHI]]
;
  br i1 %cond, label %if, label %else

if:
  call void @dummy()
  %add.1 = add i32 %a, 2
  store i32 %add.1, ptr %p
  br label %join

else:
  %add.2 = add i32 %b, 3
  store i32 %add.2, ptr %p
  br label %join

join:
  %phi = phi i32 [ %add.1, %if ], [ %add.2, %else ]
  ret i32 %phi
}

define i32 @store_and_unrelated_many_phi_add2(i1 %cond, ptr %p, i32 %a, i32 %b) {
; CHECK-LABEL: @store_and_unrelated_many_phi_add2(
; CHECK-NEXT:    br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @dummy()
; CHECK-NEXT:    [[ADD_1:%.*]] = add i32 [[A:%.*]], 2
; CHECK-NEXT:    br label [[JOIN:%.*]]
; CHECK:       else:
; CHECK-NEXT:    [[ADD_2:%.*]] = add i32 [[B:%.*]], 3
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[ADD_1]], [[IF]] ], [ [[ADD_2]], [[ELSE]] ]
; CHECK-NEXT:    [[ADD_A_2:%.*]] = add i32 [[A]], 1
; CHECK-NEXT:    store i32 [[ADD_A_2]], ptr [[P:%.*]], align 4
; CHECK-NEXT:    ret i32 [[PHI]]
;
  br i1 %cond, label %if, label %else

if:
  call void @dummy()
  %add.1 = add i32 %a, 2
  %add.a.1 = add i32 %a, 1
  store i32 %add.a.1, ptr %p
  br label %join

else:
  %add.2 = add i32 %b, 3
  %add.a.2 = add i32 %a, 1
  store i32 %add.a.2, ptr %p
  br label %join

join:
  %phi = phi i32 [ %add.1, %if ], [ %add.2, %else ]
  ret i32 %phi
}

declare void @dummy()
declare void @use.ptr(ptr)

!12 = !{i32 1}