llvm/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes=correlated-propagation -S %s | FileCheck %s

target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.10.0"

declare void @check1(i1) #1
declare void @check2(i1) #1
declare void @llvm.assume(i1)

; Make sure we propagate the value of %tmp35 to the true/false cases

define void @test1(i64 %tmp35) {
; CHECK-LABEL: @test1(
; CHECK-NEXT:  bb:
; CHECK-NEXT:    [[TMP36:%.*]] = icmp sgt i64 [[TMP35:%.*]], 0
; CHECK-NEXT:    br i1 [[TMP36]], label [[BB_TRUE:%.*]], label [[BB_FALSE:%.*]]
; CHECK:       bb_true:
; CHECK-NEXT:    tail call void @check1(i1 false) #[[ATTR2:[0-9]+]]
; CHECK-NEXT:    unreachable
; CHECK:       bb_false:
; CHECK-NEXT:    tail call void @check2(i1 true) #[[ATTR2]]
; CHECK-NEXT:    unreachable
;
bb:
  %tmp36 = icmp sgt i64 %tmp35, 0
  br i1 %tmp36, label %bb_true, label %bb_false

bb_true:
  %tmp47 = icmp slt i64 %tmp35, 0
  tail call void @check1(i1 %tmp47) #4
  unreachable

bb_false:
  %tmp48 = icmp sle i64 %tmp35, 0
  tail call void @check2(i1 %tmp48) #4
  unreachable
}

; This is the same as test1 but with a diamond to ensure we
; get %tmp36 from both true and false BBs.

define void @test2(i64 %tmp35, i1 %inner_cmp) {
; CHECK-LABEL: @test2(
; CHECK-NEXT:  bb:
; CHECK-NEXT:    [[TMP36:%.*]] = icmp sgt i64 [[TMP35:%.*]], 0
; CHECK-NEXT:    br i1 [[TMP36]], label [[BB_TRUE:%.*]], label [[BB_FALSE:%.*]]
; CHECK:       bb_true:
; CHECK-NEXT:    br i1 [[INNER_CMP:%.*]], label [[INNER_TRUE:%.*]], label [[INNER_FALSE:%.*]]
; CHECK:       inner_true:
; CHECK-NEXT:    br label [[MERGE:%.*]]
; CHECK:       inner_false:
; CHECK-NEXT:    br label [[MERGE]]
; CHECK:       merge:
; CHECK-NEXT:    tail call void @check1(i1 false)
; CHECK-NEXT:    unreachable
; CHECK:       bb_false:
; CHECK-NEXT:    tail call void @check2(i1 true) #[[ATTR2]]
; CHECK-NEXT:    unreachable
;
bb:
  %tmp36 = icmp sgt i64 %tmp35, 0
  br i1 %tmp36, label %bb_true, label %bb_false

bb_true:
  br i1 %inner_cmp, label %inner_true, label %inner_false

inner_true:
  br label %merge

inner_false:
  br label %merge

merge:
  %tmp47 = icmp slt i64 %tmp35, 0
  tail call void @check1(i1 %tmp47) #0
  unreachable

bb_false:
  %tmp48 = icmp sle i64 %tmp35, 0
  tail call void @check2(i1 %tmp48) #4
  unreachable
}

; Make sure binary operator transfer functions are run when RHS is non-constant

define i1 @test3(i32 %x, i32 %y) #0 {
; CHECK-LABEL: @test3(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[X:%.*]], 10
; CHECK-NEXT:    br i1 [[CMP1]], label [[CONT1:%.*]], label [[OUT:%.*]]
; CHECK:       cont1:
; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[Y:%.*]], 10
; CHECK-NEXT:    br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]]
; CHECK:       cont2:
; CHECK-NEXT:    [[ADD:%.*]] = add nuw nsw i32 [[X]], [[Y]]
; CHECK-NEXT:    br label [[OUT]]
; CHECK:       out:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp1 = icmp ult i32 %x, 10
  br i1 %cmp1, label %cont1, label %out

cont1:
  %cmp2 = icmp ult i32 %y, 10
  br i1 %cmp2, label %cont2, label %out

cont2:
  %add = add i32 %x, %y
  %cmp3 = icmp ult i32 %add, 25
  br label %out

out:
  %ret = phi i1 [ true, %entry], [ true, %cont1 ], [ %cmp3, %cont2 ]
  ret i1 %ret
}

; Same as previous but make sure nobody gets over-zealous

define i1 @test4(i32 %x, i32 %y) #0 {
; CHECK-LABEL: @test4(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[X:%.*]], 10
; CHECK-NEXT:    br i1 [[CMP1]], label [[CONT1:%.*]], label [[OUT:%.*]]
; CHECK:       cont1:
; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[Y:%.*]], 10
; CHECK-NEXT:    br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]]
; CHECK:       cont2:
; CHECK-NEXT:    [[ADD:%.*]] = add nuw nsw i32 [[X]], [[Y]]
; CHECK-NEXT:    [[CMP3:%.*]] = icmp ult i32 [[ADD]], 15
; CHECK-NEXT:    br label [[OUT]]
; CHECK:       out:
; CHECK-NEXT:    [[RET:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ true, [[CONT1]] ], [ [[CMP3]], [[CONT2]] ]
; CHECK-NEXT:    ret i1 [[RET]]
;
entry:
  %cmp1 = icmp ult i32 %x, 10
  br i1 %cmp1, label %cont1, label %out

cont1:
  %cmp2 = icmp ult i32 %y, 10
  br i1 %cmp2, label %cont2, label %out

cont2:
  %add = add i32 %x, %y
  %cmp3 = icmp ult i32 %add, 15
  br label %out

out:
  %ret = phi i1 [ true, %entry], [ true, %cont1 ], [ %cmp3, %cont2 ]
  ret i1 %ret
}

; Make sure binary operator transfer functions are run when RHS is non-constant

define i1 @test5(i32 %x, i32 %y) #0 {
; CHECK-LABEL: @test5(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[X:%.*]], 5
; CHECK-NEXT:    br i1 [[CMP1]], label [[CONT1:%.*]], label [[OUT:%.*]]
; CHECK:       cont1:
; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[Y:%.*]], 5
; CHECK-NEXT:    br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]]
; CHECK:       cont2:
; CHECK-NEXT:    [[SHIFTED:%.*]] = shl nuw nsw i32 [[X]], [[Y]]
; CHECK-NEXT:    br label [[OUT]]
; CHECK:       out:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp1 = icmp ult i32 %x, 5
  br i1 %cmp1, label %cont1, label %out

cont1:
  %cmp2 = icmp ult i32 %y, 5
  br i1 %cmp2, label %cont2, label %out

cont2:
  %shifted = shl i32 %x, %y
  %cmp3 = icmp ult i32 %shifted, 65536
  br label %out

out:
  %ret = phi i1 [ true, %entry], [ true, %cont1 ], [ %cmp3, %cont2 ]
  ret i1 %ret
}

; Same as previous but make sure nobody gets over-zealous

define i1 @test6(i32 %x, i32 %y) #0 {
; CHECK-LABEL: @test6(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[X:%.*]], 5
; CHECK-NEXT:    br i1 [[CMP1]], label [[CONT1:%.*]], label [[OUT:%.*]]
; CHECK:       cont1:
; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[Y:%.*]], 15
; CHECK-NEXT:    br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]]
; CHECK:       cont2:
; CHECK-NEXT:    [[SHIFTED:%.*]] = shl nuw nsw i32 [[X]], [[Y]]
; CHECK-NEXT:    [[CMP3:%.*]] = icmp ult i32 [[SHIFTED]], 65536
; CHECK-NEXT:    br label [[OUT]]
; CHECK:       out:
; CHECK-NEXT:    [[RET:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ true, [[CONT1]] ], [ [[CMP3]], [[CONT2]] ]
; CHECK-NEXT:    ret i1 [[RET]]
;
entry:
  %cmp1 = icmp ult i32 %x, 5
  br i1 %cmp1, label %cont1, label %out

cont1:
  %cmp2 = icmp ult i32 %y, 15
  br i1 %cmp2, label %cont2, label %out

cont2:
  %shifted = shl i32 %x, %y
  %cmp3 = icmp ult i32 %shifted, 65536
  br label %out

out:
  %ret = phi i1 [ true, %entry], [ true, %cont1 ], [ %cmp3, %cont2 ]
  ret i1 %ret
}

define i1 @test7(i32 %a, i32 %b) {
; CHECK-LABEL: @test7(
; CHECK-NEXT:  begin:
; CHECK-NEXT:    [[CMP0:%.*]] = icmp sge i32 [[A:%.*]], 0
; CHECK-NEXT:    [[CMP1:%.*]] = icmp sge i32 [[B:%.*]], 0
; CHECK-NEXT:    [[BR:%.*]] = and i1 [[CMP0]], [[CMP1]]
; CHECK-NEXT:    br i1 [[BR]], label [[BB:%.*]], label [[EXIT:%.*]]
; CHECK:       bb:
; CHECK-NEXT:    [[ADD:%.*]] = add nuw i32 [[A]], [[B]]
; CHECK-NEXT:    [[RES:%.*]] = icmp sge i32 [[ADD]], 0
; CHECK-NEXT:    br label [[EXIT]]
; CHECK:       exit:
; CHECK-NEXT:    [[IV:%.*]] = phi i1 [ true, [[BEGIN:%.*]] ], [ [[RES]], [[BB]] ]
; CHECK-NEXT:    ret i1 [[IV]]
;
begin:
  %cmp0 = icmp sge i32 %a, 0
  %cmp1 = icmp sge i32 %b, 0
  %br = and i1 %cmp0, %cmp1
  br i1 %br, label %bb, label %exit

bb:
  %add = add i32 %a, %b
  %res = icmp sge i32 %add, 0
  br label %exit

exit:
  %iv = phi i1 [ true, %begin ], [ %res, %bb ]
  ret i1 %iv
}

define i1 @test8(i32 %a, i32 %b) {
; CHECK-LABEL: @test8(
; CHECK-NEXT:  begin:
; CHECK-NEXT:    [[CMP0:%.*]] = icmp sge i32 [[A:%.*]], 0
; CHECK-NEXT:    [[CMP1:%.*]] = icmp sge i32 [[B:%.*]], 0
; CHECK-NEXT:    [[BR:%.*]] = and i1 [[CMP0]], [[CMP1]]
; CHECK-NEXT:    br i1 [[BR]], label [[BB:%.*]], label [[EXIT:%.*]]
; CHECK:       bb:
; CHECK-NEXT:    [[ADD:%.*]] = add nuw nsw i32 [[A]], [[B]]
; CHECK-NEXT:    br label [[EXIT]]
; CHECK:       exit:
; CHECK-NEXT:    ret i1 true
;
begin:
  %cmp0 = icmp sge i32 %a, 0
  %cmp1 = icmp sge i32 %b, 0
  %br = and i1 %cmp0, %cmp1
  br i1 %br, label %bb, label %exit

bb:
  %add = add nsw i32 %a, %b
  %res = icmp sge i32 %add, 0
  br label %exit

exit:
  %iv = phi i1 [ true, %begin ], [ %res, %bb ]
  ret i1 %iv
}

define i1 @test10(i32 %a, i32 %b) {
; CHECK-LABEL: @test10(
; CHECK-NEXT:  begin:
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[A:%.*]], -256
; CHECK-NEXT:    br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]]
; CHECK:       bb:
; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[A]], [[B:%.*]]
; CHECK-NEXT:    [[RES:%.*]] = icmp uge i32 [[ADD]], -256
; CHECK-NEXT:    br label [[EXIT]]
; CHECK:       exit:
; CHECK-NEXT:    [[IV:%.*]] = phi i1 [ true, [[BEGIN:%.*]] ], [ [[RES]], [[BB]] ]
; CHECK-NEXT:    ret i1 [[IV]]
;
begin:
  %cmp = icmp uge i32 %a, 4294967040
  br i1 %cmp, label %bb, label %exit

bb:
  %add = add i32 %a, %b
  %res = icmp uge i32 %add, 4294967040
  br label %exit

exit:
  %iv = phi i1 [ true, %begin ], [ %res, %bb ]
  ret i1 %iv
}

define i1 @test11(i32 %a, i32 %b) {
; CHECK-LABEL: @test11(
; CHECK-NEXT:  begin:
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[A:%.*]], -256
; CHECK-NEXT:    br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]]
; CHECK:       bb:
; CHECK-NEXT:    [[ADD:%.*]] = add nuw i32 [[A]], [[B:%.*]]
; CHECK-NEXT:    br label [[EXIT]]
; CHECK:       exit:
; CHECK-NEXT:    ret i1 true
;
begin:
  %cmp = icmp uge i32 %a, 4294967040
  br i1 %cmp, label %bb, label %exit

bb:
  %add = add nuw i32 %a, %b
  %res = icmp uge i32 %add, 4294967040
  br label %exit

exit:
  %iv = phi i1 [ true, %begin ], [ %res, %bb ]
  ret i1 %iv
}

define i1 @test12(i32 %x) {
; CHECK-LABEL: @test12(
; CHECK-NEXT:    [[ZEXT:%.*]] = zext i32 [[X:%.*]] to i64
; CHECK-NEXT:    [[MUL:%.*]] = mul nuw nsw i64 [[ZEXT]], 7
; CHECK-NEXT:    [[SHR:%.*]] = lshr i64 [[MUL]], 32
; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i64 [[SHR]] to i32
; CHECK-NEXT:    ret i1 true
;
  %zext = zext i32 %x to i64
  %mul = mul nuw i64 %zext, 7
  %shr = lshr i64 %mul, 32
  %trunc = trunc i64 %shr to i32
  %cmp = icmp ult i32 %trunc, 7
  ret i1 %cmp
}

define i1 @test13(i8 %x, ptr %p) {
; CHECK-LABEL: @test13(
; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i64
; CHECK-NEXT:    [[ADD:%.*]] = add nuw nsw i64 [[ZEXT]], 128
; CHECK-NEXT:    store i64 [[ADD]], ptr [[P:%.*]], align 8
; CHECK-NEXT:    ret i1 true
;
  %zext = zext i8 %x to i64
  %add = add nuw nsw i64 %zext, 128
  %cmp = icmp ult i64 %add, 384
  ; Without this extra use, InstSimplify could handle this
  store i64 %add, ptr %p
  ret i1 %cmp
}

define i1 @test14(i32 %a, i32 %b) {
; CHECK-LABEL: @test14(
; CHECK-NEXT:  begin:
; CHECK-NEXT:    [[CMP0:%.*]] = icmp sge i32 [[A:%.*]], 0
; CHECK-NEXT:    [[CMP1:%.*]] = icmp sge i32 [[B:%.*]], 0
; CHECK-NEXT:    [[BR:%.*]] = and i1 [[CMP0]], [[CMP1]]
; CHECK-NEXT:    br i1 [[BR]], label [[BB:%.*]], label [[EXIT:%.*]]
; CHECK:       bb:
; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[A]], [[B]]
; CHECK-NEXT:    [[RES:%.*]] = icmp sge i32 [[SUB]], 0
; CHECK-NEXT:    br label [[EXIT]]
; CHECK:       exit:
; CHECK-NEXT:    [[IV:%.*]] = phi i1 [ true, [[BEGIN:%.*]] ], [ [[RES]], [[BB]] ]
; CHECK-NEXT:    ret i1 [[IV]]
;
begin:
  %cmp0 = icmp sge i32 %a, 0
  %cmp1 = icmp sge i32 %b, 0
  %br = and i1 %cmp0, %cmp1
  br i1 %br, label %bb, label %exit

bb:
  %sub = sub i32 %a, %b
  %res = icmp sge i32 %sub, 0
  br label %exit

exit:
  %iv = phi i1 [ true, %begin ], [ %res, %bb ]
  ret i1 %iv
}

define i1 @test15(i32 %a, i32 %b) {
; CHECK-LABEL: @test15(
; CHECK-NEXT:  begin:
; CHECK-NEXT:    [[CMP0:%.*]] = icmp sge i32 [[A:%.*]], 0
; CHECK-NEXT:    [[CMP1:%.*]] = icmp sge i32 [[B:%.*]], 0
; CHECK-NEXT:    [[BR:%.*]] = and i1 [[CMP0]], [[CMP1]]
; CHECK-NEXT:    br i1 [[BR]], label [[BB:%.*]], label [[EXIT:%.*]]
; CHECK:       bb:
; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[A]], [[B]]
; CHECK-NEXT:    [[RES:%.*]] = icmp sge i32 [[SUB]], 0
; CHECK-NEXT:    br label [[EXIT]]
; CHECK:       exit:
; CHECK-NEXT:    [[IV:%.*]] = phi i1 [ true, [[BEGIN:%.*]] ], [ [[RES]], [[BB]] ]
; CHECK-NEXT:    ret i1 [[IV]]
;
begin:
  %cmp0 = icmp sge i32 %a, 0
  %cmp1 = icmp sge i32 %b, 0
  %br = and i1 %cmp0, %cmp1
  br i1 %br, label %bb, label %exit

bb:
  %sub = sub nsw i32 %a, %b
  %res = icmp sge i32 %sub, 0
  br label %exit

exit:
  %iv = phi i1 [ true, %begin ], [ %res, %bb ]
  ret i1 %iv
}

define i1 @test16(i32 %a, i32 %b) {
; CHECK-LABEL: @test16(
; CHECK-NEXT:  begin:
; CHECK-NEXT:    [[CMP0:%.*]] = icmp sge i32 [[A:%.*]], 0
; CHECK-NEXT:    [[CMP1:%.*]] = icmp sge i32 [[B:%.*]], 0
; CHECK-NEXT:    [[BR:%.*]] = and i1 [[CMP0]], [[CMP1]]
; CHECK-NEXT:    br i1 [[BR]], label [[BB:%.*]], label [[EXIT:%.*]]
; CHECK:       bb:
; CHECK-NEXT:    [[SUB:%.*]] = sub nuw nsw i32 [[A]], [[B]]
; CHECK-NEXT:    br label [[EXIT]]
; CHECK:       exit:
; CHECK-NEXT:    ret i1 true
;
begin:
  %cmp0 = icmp sge i32 %a, 0
  %cmp1 = icmp sge i32 %b, 0
  %br = and i1 %cmp0, %cmp1
  br i1 %br, label %bb, label %exit

bb:
  %sub = sub nuw i32 %a, %b
  %res = icmp sge i32 %sub, 0
  br label %exit

exit:
  %iv = phi i1 [ true, %begin ], [ %res, %bb ]
  ret i1 %iv
}

define i1 @test17(i32 %a, i32 %b) {
; CHECK-LABEL: @test17(
; CHECK-NEXT:  begin:
; CHECK-NEXT:    [[CMP0:%.*]] = icmp sle i32 [[A:%.*]], 0
; CHECK-NEXT:    [[CMP1:%.*]] = icmp sge i32 [[B:%.*]], 0
; CHECK-NEXT:    [[BR:%.*]] = and i1 [[CMP0]], [[CMP1]]
; CHECK-NEXT:    br i1 [[BR]], label [[BB:%.*]], label [[EXIT:%.*]]
; CHECK:       bb:
; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[A]], [[B]]
; CHECK-NEXT:    [[RES:%.*]] = icmp sle i32 [[SUB]], 0
; CHECK-NEXT:    br label [[EXIT]]
; CHECK:       exit:
; CHECK-NEXT:    [[IV:%.*]] = phi i1 [ true, [[BEGIN:%.*]] ], [ [[RES]], [[BB]] ]
; CHECK-NEXT:    ret i1 [[IV]]
;
begin:
  %cmp0 = icmp sle i32 %a, 0
  %cmp1 = icmp sge i32 %b, 0
  %br = and i1 %cmp0, %cmp1
  br i1 %br, label %bb, label %exit

bb:
  %sub = sub i32 %a, %b
  %res = icmp sle i32 %sub, 0
  br label %exit

exit:
  %iv = phi i1 [ true, %begin ], [ %res, %bb ]
  ret i1 %iv
}

define i1 @test18(i32 %a, i32 %b) {
; CHECK-LABEL: @test18(
; CHECK-NEXT:  begin:
; CHECK-NEXT:    [[CMP0:%.*]] = icmp sle i32 [[A:%.*]], 0
; CHECK-NEXT:    [[CMP1:%.*]] = icmp sge i32 [[B:%.*]], 0
; CHECK-NEXT:    [[BR:%.*]] = and i1 [[CMP0]], [[CMP1]]
; CHECK-NEXT:    br i1 [[BR]], label [[BB:%.*]], label [[EXIT:%.*]]
; CHECK:       bb:
; CHECK-NEXT:    [[SUB:%.*]] = sub nuw i32 [[A]], [[B]]
; CHECK-NEXT:    [[RES:%.*]] = icmp sle i32 [[SUB]], 0
; CHECK-NEXT:    br label [[EXIT]]
; CHECK:       exit:
; CHECK-NEXT:    [[IV:%.*]] = phi i1 [ true, [[BEGIN:%.*]] ], [ [[RES]], [[BB]] ]
; CHECK-NEXT:    ret i1 [[IV]]
;
begin:
  %cmp0 = icmp sle i32 %a, 0
  %cmp1 = icmp sge i32 %b, 0
  %br = and i1 %cmp0, %cmp1
  br i1 %br, label %bb, label %exit

bb:
  %sub = sub nuw i32 %a, %b
  %res = icmp sle i32 %sub, 0
  br label %exit

exit:
  %iv = phi i1 [ true, %begin ], [ %res, %bb ]
  ret i1 %iv
}

define i1 @test19(i32 %a, i32 %b) {
; CHECK-LABEL: @test19(
; CHECK-NEXT:  begin:
; CHECK-NEXT:    [[CMP0:%.*]] = icmp sle i32 [[A:%.*]], 0
; CHECK-NEXT:    [[CMP1:%.*]] = icmp sge i32 [[B:%.*]], 0
; CHECK-NEXT:    [[BR:%.*]] = and i1 [[CMP0]], [[CMP1]]
; CHECK-NEXT:    br i1 [[BR]], label [[BB:%.*]], label [[EXIT:%.*]]
; CHECK:       bb:
; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[A]], [[B]]
; CHECK-NEXT:    br label [[EXIT]]
; CHECK:       exit:
; CHECK-NEXT:    ret i1 true
;
begin:
  %cmp0 = icmp sle i32 %a, 0
  %cmp1 = icmp sge i32 %b, 0
  %br = and i1 %cmp0, %cmp1
  br i1 %br, label %bb, label %exit

bb:
  %sub = sub nsw i32 %a, %b
  %res = icmp sle i32 %sub, 0
  br label %exit

exit:
  %iv = phi i1 [ true, %begin ], [ %res, %bb ]
  ret i1 %iv
}

define i1 @test_br_cmp_with_offset(i64 %idx) {
; CHECK-LABEL: @test_br_cmp_with_offset(
; CHECK-NEXT:    [[IDX_OFF1:%.*]] = add i64 [[IDX:%.*]], -5
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i64 [[IDX_OFF1]], 3
; CHECK-NEXT:    br i1 [[CMP1]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK:       if.true:
; CHECK-NEXT:    [[IDX_OFF2:%.*]] = add nsw i64 [[IDX]], -1
; CHECK-NEXT:    ret i1 true
; CHECK:       if.false:
; CHECK-NEXT:    ret i1 undef
;
  %idx.off1 = add i64 %idx, -5
  %cmp1 = icmp ult i64 %idx.off1, 3
  br i1 %cmp1, label %if.true, label %if.false

if.true:
  %idx.off2 = add i64 %idx, -1
  %cmp2 = icmp ult i64 %idx.off2, 10
  ret i1 %cmp2

if.false:
  ret i1 undef
}

define i1 @test_assume_cmp_with_offset(i64 %idx) {
; CHECK-LABEL: @test_assume_cmp_with_offset(
; CHECK-NEXT:    [[IDX_OFF1:%.*]] = add i64 [[IDX:%.*]], -5
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i64 [[IDX_OFF1]], 3
; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP1]])
; CHECK-NEXT:    [[IDX_OFF2:%.*]] = add nsw i64 [[IDX]], -1
; CHECK-NEXT:    ret i1 true
;
  %idx.off1 = add i64 %idx, -5
  %cmp1 = icmp ult i64 %idx.off1, 3
  tail call void @llvm.assume(i1 %cmp1)
  %idx.off2 = add i64 %idx, -1
  %cmp2 = icmp ult i64 %idx.off2, 10
  ret i1 %cmp2
}

define i1 @test_assume_cmp_with_offset_or(i64 %idx, i1 %other) {
; CHECK-LABEL: @test_assume_cmp_with_offset_or(
; CHECK-NEXT:    [[IDX_OFF1:%.*]] = or disjoint i64 [[IDX:%.*]], 5
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i64 [[IDX_OFF1]], 10
; CHECK-NEXT:    br i1 [[CMP1]], label [[T:%.*]], label [[F:%.*]]
; CHECK:       T:
; CHECK-NEXT:    ret i1 true
; CHECK:       F:
; CHECK-NEXT:    ret i1 [[OTHER:%.*]]
;
  %idx.off1 = or disjoint i64 %idx, 5
  %cmp1 = icmp ugt i64 %idx.off1, 10
  br i1 %cmp1, label %T, label %F
T:
  %cmp2 = icmp ugt i64 %idx, 2
  ret i1 %cmp2
F:
  ret i1 %other
}

define void @test_cmp_phi(i8 %a) {
; CHECK-LABEL: @test_cmp_phi(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[C0:%.*]] = icmp ult i8 [[A:%.*]], 2
; CHECK-NEXT:    br i1 [[C0]], label [[LOOP:%.*]], label [[EXIT:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    [[P:%.*]] = phi i8 [ [[A]], [[ENTRY:%.*]] ], [ [[B:%.*]], [[LOOP]] ]
; CHECK-NEXT:    [[C1:%.*]] = icmp ne i8 [[P]], 0
; CHECK-NEXT:    [[C4:%.*]] = call i1 @get_bool()
; CHECK-NEXT:    [[B]] = zext i1 [[C4]] to i8
; CHECK-NEXT:    br i1 [[C1]], label [[LOOP]], label [[EXIT]]
; CHECK:       exit:
; CHECK-NEXT:    ret void
;
entry:
  %c0 = icmp ult i8 %a, 2
  br i1 %c0, label %loop, label %exit

loop:
  %p = phi i8 [ %a, %entry ], [ %b, %loop ]
  %c1 = icmp ne i8 %p, 0
  %c2 = icmp ne i8 %p, 2
  %c3 = and i1 %c1, %c2
  %c4 = call i1 @get_bool()
  %b = zext i1 %c4 to i8
  br i1 %c3, label %loop, label %exit

exit:
  ret void
}

declare i1 @get_bool()

define void @test_icmp_or_ult(i32 %a, i32 %b) {
; CHECK-LABEL: @test_icmp_or_ult(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[OR:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[OR]], 42
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK:       if.true:
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    ret void
; CHECK:       if.false:
; CHECK-NEXT:    [[CMP4:%.*]] = icmp uge i32 [[A]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP4]])
; CHECK-NEXT:    [[CMP5:%.*]] = icmp uge i32 [[B]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP5]])
; CHECK-NEXT:    ret void
;
entry:
  %or = or i32 %a, %b
  %cmp = icmp ult i32 %or, 42
  br i1 %cmp, label %if.true, label %if.false

if.true:
  %cmp2 = icmp ult i32 %a, 42
  call void @check1(i1 %cmp2)
  %cmp3 = icmp ult i32 %b, 42
  call void @check1(i1 %cmp3)
  ret void

if.false:
  %cmp4 = icmp uge i32 %a, 42
  call void @check1(i1 %cmp4)
  %cmp5 = icmp uge i32 %b, 42
  call void @check1(i1 %cmp5)
  ret void
}

define void @test_icmp_or_ule(i32 %a, i32 %b) {
; CHECK-LABEL: @test_icmp_or_ule(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[OR:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i32 [[OR]], 42
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK:       if.true:
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    ret void
; CHECK:       if.false:
; CHECK-NEXT:    [[CMP4:%.*]] = icmp ugt i32 [[A]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP4]])
; CHECK-NEXT:    [[CMP5:%.*]] = icmp ugt i32 [[B]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP5]])
; CHECK-NEXT:    ret void
;
entry:
  %or = or i32 %a, %b
  %cmp = icmp ule i32 %or, 42
  br i1 %cmp, label %if.true, label %if.false

if.true:
  %cmp2 = icmp ule i32 %a, 42
  call void @check1(i1 %cmp2)
  %cmp3 = icmp ule i32 %b, 42
  call void @check1(i1 %cmp3)
  ret void

if.false:
  %cmp4 = icmp ugt i32 %a, 42
  call void @check1(i1 %cmp4)
  %cmp5 = icmp ugt i32 %b, 42
  call void @check1(i1 %cmp5)
  ret void
}

define void @test_icmp_or_ugt(i32 %a, i32 %b) {
; CHECK-LABEL: @test_icmp_or_ugt(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[OR:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[OR]], 42
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK:       if.true:
; CHECK-NEXT:    [[CMP2:%.*]] = icmp ugt i32 [[A]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP2]])
; CHECK-NEXT:    [[CMP3:%.*]] = icmp ugt i32 [[B]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP3]])
; CHECK-NEXT:    ret void
; CHECK:       if.false:
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    ret void
;
entry:
  %or = or i32 %a, %b
  %cmp = icmp ugt i32 %or, 42
  br i1 %cmp, label %if.true, label %if.false

if.true:
  %cmp2 = icmp ugt i32 %a, 42
  call void @check1(i1 %cmp2)
  %cmp3 = icmp ugt i32 %b, 42
  call void @check1(i1 %cmp3)
  ret void

if.false:
  %cmp4 = icmp ule i32 %a, 42
  call void @check1(i1 %cmp4)
  %cmp5 = icmp ule i32 %b, 42
  call void @check1(i1 %cmp5)
  ret void
}

define void @test_icmp_or_uge(i32 %a, i32 %b) {
; CHECK-LABEL: @test_icmp_or_uge(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[OR:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[OR]], 42
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK:       if.true:
; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i32 [[A]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP2]])
; CHECK-NEXT:    [[CMP3:%.*]] = icmp uge i32 [[B]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP3]])
; CHECK-NEXT:    ret void
; CHECK:       if.false:
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    ret void
;
entry:
  %or = or i32 %a, %b
  %cmp = icmp uge i32 %or, 42
  br i1 %cmp, label %if.true, label %if.false

if.true:
  %cmp2 = icmp uge i32 %a, 42
  call void @check1(i1 %cmp2)
  %cmp3 = icmp uge i32 %b, 42
  call void @check1(i1 %cmp3)
  ret void

if.false:
  %cmp4 = icmp ult i32 %a, 42
  call void @check1(i1 %cmp4)
  %cmp5 = icmp ult i32 %b, 42
  call void @check1(i1 %cmp5)
  ret void
}

define void @test_icmp_or_slt(i32 %a, i32 %b) {
; CHECK-LABEL: @test_icmp_or_slt(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[OR:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[OR]], 42
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK:       if.true:
; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[A]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP2]])
; CHECK-NEXT:    [[CMP3:%.*]] = icmp slt i32 [[B]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP3]])
; CHECK-NEXT:    ret void
; CHECK:       if.false:
; CHECK-NEXT:    [[CMP4:%.*]] = icmp sge i32 [[A]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP4]])
; CHECK-NEXT:    [[CMP5:%.*]] = icmp sge i32 [[B]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP5]])
; CHECK-NEXT:    ret void
;
entry:
  %or = or i32 %a, %b
  %cmp = icmp slt i32 %or, 42
  br i1 %cmp, label %if.true, label %if.false

if.true:
  %cmp2 = icmp slt i32 %a, 42
  call void @check1(i1 %cmp2)
  %cmp3 = icmp slt i32 %b, 42
  call void @check1(i1 %cmp3)
  ret void

if.false:
  %cmp4 = icmp sge i32 %a, 42
  call void @check1(i1 %cmp4)
  %cmp5 = icmp sge i32 %b, 42
  call void @check1(i1 %cmp5)
  ret void
}

define void @test_icmp_and_ugt(i32 %a, i32 %b) {
; CHECK-LABEL: @test_icmp_and_ugt(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[AND]], 42
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK:       if.true:
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    ret void
; CHECK:       if.false:
; CHECK-NEXT:    [[CMP4:%.*]] = icmp ule i32 [[A]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP4]])
; CHECK-NEXT:    [[CMP5:%.*]] = icmp ule i32 [[B]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP5]])
; CHECK-NEXT:    ret void
;
entry:
  %and = and i32 %a, %b
  %cmp = icmp ugt i32 %and, 42
  br i1 %cmp, label %if.true, label %if.false

if.true:
  %cmp2 = icmp ugt i32 %a, 42
  call void @check1(i1 %cmp2)
  %cmp3 = icmp ugt i32 %b, 42
  call void @check1(i1 %cmp3)
  ret void

if.false:
  %cmp4 = icmp ule i32 %a, 42
  call void @check1(i1 %cmp4)
  %cmp5 = icmp ule i32 %b, 42
  call void @check1(i1 %cmp5)
  ret void
}

define void @test_icmp_and_uge(i32 %a, i32 %b) {
; CHECK-LABEL: @test_icmp_and_uge(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[AND]], 42
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK:       if.true:
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    ret void
; CHECK:       if.false:
; CHECK-NEXT:    [[CMP4:%.*]] = icmp ult i32 [[A]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP4]])
; CHECK-NEXT:    [[CMP5:%.*]] = icmp ult i32 [[B]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP5]])
; CHECK-NEXT:    ret void
;
entry:
  %and = and i32 %a, %b
  %cmp = icmp uge i32 %and, 42
  br i1 %cmp, label %if.true, label %if.false

if.true:
  %cmp2 = icmp uge i32 %a, 42
  call void @check1(i1 %cmp2)
  %cmp3 = icmp uge i32 %b, 42
  call void @check1(i1 %cmp3)
  ret void

if.false:
  %cmp4 = icmp ult i32 %a, 42
  call void @check1(i1 %cmp4)
  %cmp5 = icmp ult i32 %b, 42
  call void @check1(i1 %cmp5)
  ret void
}

define void @test_icmp_and_ult(i32 %a, i32 %b) {
; CHECK-LABEL: @test_icmp_and_ult(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[AND]], 42
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK:       if.true:
; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[A]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP2]])
; CHECK-NEXT:    [[CMP3:%.*]] = icmp ult i32 [[B]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP3]])
; CHECK-NEXT:    ret void
; CHECK:       if.false:
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    ret void
;
entry:
  %and = and i32 %a, %b
  %cmp = icmp ult i32 %and, 42
  br i1 %cmp, label %if.true, label %if.false

if.true:
  %cmp2 = icmp ult i32 %a, 42
  call void @check1(i1 %cmp2)
  %cmp3 = icmp ult i32 %b, 42
  call void @check1(i1 %cmp3)
  ret void

if.false:
  %cmp4 = icmp uge i32 %a, 42
  call void @check1(i1 %cmp4)
  %cmp5 = icmp uge i32 %b, 42
  call void @check1(i1 %cmp5)
  ret void
}

define void @test_icmp_and_sgt(i32 %a, i32 %b) {
; CHECK-LABEL: @test_icmp_and_sgt(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[AND]], 42
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK:       if.true:
; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i32 [[A]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP2]])
; CHECK-NEXT:    [[CMP3:%.*]] = icmp sgt i32 [[B]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP3]])
; CHECK-NEXT:    ret void
; CHECK:       if.false:
; CHECK-NEXT:    [[CMP4:%.*]] = icmp sle i32 [[A]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP4]])
; CHECK-NEXT:    [[CMP5:%.*]] = icmp sle i32 [[B]], 42
; CHECK-NEXT:    call void @check1(i1 [[CMP5]])
; CHECK-NEXT:    ret void
;
entry:
  %and = and i32 %a, %b
  %cmp = icmp sgt i32 %and, 42
  br i1 %cmp, label %if.true, label %if.false

if.true:
  %cmp2 = icmp sgt i32 %a, 42
  call void @check1(i1 %cmp2)
  %cmp3 = icmp sgt i32 %b, 42
  call void @check1(i1 %cmp3)
  ret void

if.false:
  %cmp4 = icmp sle i32 %a, 42
  call void @check1(i1 %cmp4)
  %cmp5 = icmp sle i32 %b, 42
  call void @check1(i1 %cmp5)
  ret void
}

define void @test_icmp_mask_eq_two_values(i32 %a) {
; CHECK-LABEL: @test_icmp_mask_eq_two_values(
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], -2
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 10
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK:       if.true:
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    call void @check1(i1 false)
; CHECK-NEXT:    call void @check1(i1 false)
; CHECK-NEXT:    ret void
; CHECK:       if.false:
; CHECK-NEXT:    ret void
;
  %and = and i32 %a, -2
  %cmp = icmp eq i32 %and, 10
  br i1 %cmp, label %if.true, label %if.false

if.true:
  %cmp2 = icmp uge i32 %a, 10
  call void @check1(i1 %cmp2)
  %cmp3 = icmp ule i32 %a, 11
  call void @check1(i1 %cmp3)
  %cmp4 = icmp ult i32 %a, 10
  call void @check1(i1 %cmp4)
  %cmp5 = icmp ugt i32 %a, 11
  call void @check1(i1 %cmp5)
  ret void

if.false:
  ret void
}

define void @test_icmp_mask_eq_bit_set(i32 %a) {
; CHECK-LABEL: @test_icmp_mask_eq_bit_set(
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], 32
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 32
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK:       if.true:
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    [[CMP3:%.*]] = icmp uge i32 [[A]], 33
; CHECK-NEXT:    call void @check1(i1 [[CMP3]])
; CHECK-NEXT:    ret void
; CHECK:       if.false:
; CHECK-NEXT:    ret void
;
  %and = and i32 %a, 32
  %cmp = icmp eq i32 %and, 32
  br i1 %cmp, label %if.true, label %if.false

if.true:
  %cmp2 = icmp uge i32 %a, 32
  call void @check1(i1 %cmp2)
  %cmp3 = icmp uge i32 %a, 33
  call void @check1(i1 %cmp3)
  ret void

if.false:
  ret void
}

define void @test_icmp_mask_eq_bit_unset(i32 %a) {
; CHECK-LABEL: @test_icmp_mask_eq_bit_unset(
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], 32
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK:       if.true:
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    [[CMP3:%.*]] = icmp ule i32 [[A]], -34
; CHECK-NEXT:    call void @check1(i1 [[CMP3]])
; CHECK-NEXT:    ret void
; CHECK:       if.false:
; CHECK-NEXT:    ret void
;
  %and = and i32 %a, 32
  %cmp = icmp eq i32 %and, 0
  br i1 %cmp, label %if.true, label %if.false

if.true:
  %cmp2 = icmp ule i32 %a, -33
  call void @check1(i1 %cmp2)
  %cmp3 = icmp ule i32 %a, -34
  call void @check1(i1 %cmp3)
  ret void

if.false:
  ret void
}

define void @test_icmp_mask_eq_wrong_predicate(i32 %a) {
; CHECK-LABEL: @test_icmp_mask_eq_wrong_predicate(
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], -2
; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[AND]], 10
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK:       if.true:
; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i32 [[A]], 10
; CHECK-NEXT:    call void @check1(i1 [[CMP2]])
; CHECK-NEXT:    [[CMP3:%.*]] = icmp ule i32 [[A]], 11
; CHECK-NEXT:    call void @check1(i1 [[CMP3]])
; CHECK-NEXT:    [[CMP4:%.*]] = icmp ult i32 [[A]], 10
; CHECK-NEXT:    call void @check1(i1 [[CMP4]])
; CHECK-NEXT:    [[CMP5:%.*]] = icmp ugt i32 [[A]], 11
; CHECK-NEXT:    call void @check1(i1 [[CMP5]])
; CHECK-NEXT:    ret void
; CHECK:       if.false:
; CHECK-NEXT:    ret void
;
  %and = and i32 %a, -2
  %cmp = icmp ne i32 %and, 10
  br i1 %cmp, label %if.true, label %if.false

if.true:
  %cmp2 = icmp uge i32 %a, 10
  call void @check1(i1 %cmp2)
  %cmp3 = icmp ule i32 %a, 11
  call void @check1(i1 %cmp3)
  %cmp4 = icmp ult i32 %a, 10
  call void @check1(i1 %cmp4)
  %cmp5 = icmp ugt i32 %a, 11
  call void @check1(i1 %cmp5)
  ret void

if.false:
  ret void
}

define void @test_icmp_mask_ne(i32 %a) {
; CHECK-LABEL: @test_icmp_mask_ne(
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], 6
; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[AND]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK:       if.true:
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    [[CMP3:%.*]] = icmp ugt i32 [[A]], 2
; CHECK-NEXT:    call void @check1(i1 [[CMP3]])
; CHECK-NEXT:    [[CMP4:%.*]] = icmp ult i32 [[A]], -1
; CHECK-NEXT:    call void @check1(i1 [[CMP4]])
; CHECK-NEXT:    ret void
; CHECK:       if.false:
; CHECK-NEXT:    ret void
;
  %and = and i32 %a, 6
  %cmp = icmp ne i32 %and, 0
  br i1 %cmp, label %if.true, label %if.false

if.true:
  %cmp2 = icmp uge i32 %a, 2
  call void @check1(i1 %cmp2)
  %cmp3 = icmp ugt i32 %a, 2
  call void @check1(i1 %cmp3)
  %cmp4 = icmp ult i32 %a, -1
  call void @check1(i1 %cmp4)
  ret void

if.false:
  ret void
}

define void @test_icmp_mask_ne_nonzero_cmp(i32 %a) {
; CHECK-LABEL: @test_icmp_mask_ne_nonzero_cmp(
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], 6
; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[AND]], 6
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK:       if.true:
; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i32 [[A]], 2
; CHECK-NEXT:    call void @check1(i1 [[CMP2]])
; CHECK-NEXT:    [[CMP3:%.*]] = icmp ugt i32 [[A]], 2
; CHECK-NEXT:    call void @check1(i1 [[CMP3]])
; CHECK-NEXT:    [[CMP4:%.*]] = icmp ult i32 [[A]], -1
; CHECK-NEXT:    call void @check1(i1 [[CMP4]])
; CHECK-NEXT:    ret void
; CHECK:       if.false:
; CHECK-NEXT:    ret void
;
  %and = and i32 %a, 6
  %cmp = icmp ne i32 %and, 6
  br i1 %cmp, label %if.true, label %if.false

if.true:
  %cmp2 = icmp uge i32 %a, 2
  call void @check1(i1 %cmp2)
  %cmp3 = icmp ugt i32 %a, 2
  call void @check1(i1 %cmp3)
  %cmp4 = icmp ult i32 %a, -1
  call void @check1(i1 %cmp4)
  ret void

if.false:
  ret void
}

define void @test_icmp_mask_ne_zero_mask(i32 %a) {
; CHECK-LABEL: @test_icmp_mask_ne_zero_mask(
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[A:%.*]], 0
; CHECK-NEXT:    br i1 false, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK:       if.true:
; CHECK-NEXT:    [[CMP2:%.*]] = icmp ne i32 [[A]], 0
; CHECK-NEXT:    call void @check1(i1 [[CMP2]])
; CHECK-NEXT:    ret void
; CHECK:       if.false:
; CHECK-NEXT:    ret void
;
  %and = and i32 %a, 0
  %cmp = icmp ne i32 %and, 0
  br i1 %cmp, label %if.true, label %if.false

if.true:
  %cmp2 = icmp ne i32 %a, 0
  call void @check1(i1 %cmp2)
  ret void

if.false:
  ret void
}

define void @non_const_range(i32 %a, i32 %b) {
; CHECK-LABEL: @non_const_range(
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[A:%.*]], 11
; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[B:%.*]], 21
; CHECK-NEXT:    [[AND:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false
; CHECK-NEXT:    br i1 [[AND]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK:       if:
; CHECK-NEXT:    [[A_100:%.*]] = add nuw nsw i32 [[A]], 100
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    call void @check1(i1 false)
; CHECK-NEXT:    [[A_10:%.*]] = add nuw nsw i32 [[A]], 10
; CHECK-NEXT:    [[CMP5:%.*]] = icmp ne i32 [[A_10]], [[B]]
; CHECK-NEXT:    call void @check1(i1 [[CMP5]])
; CHECK-NEXT:    [[CMP6:%.*]] = icmp eq i32 [[A_10]], [[B]]
; CHECK-NEXT:    call void @check1(i1 [[CMP6]])
; CHECK-NEXT:    ret void
; CHECK:       else:
; CHECK-NEXT:    ret void
;
  %cmp1 = icmp ult i32 %a, 11
  %cmp2 = icmp ult i32 %b, 21
  %and = select i1 %cmp1, i1 %cmp2, i1 false
  br i1 %and, label %if, label %else

if:
  %a.100 = add nuw nsw i32 %a, 100
  %cmp3 = icmp ne i32 %a.100, %b
  call void @check1(i1 %cmp3)
  %cmp4 = icmp eq i32 %a.100, %b
  call void @check1(i1 %cmp4)

  %a.10 = add nuw nsw i32 %a, 10
  %cmp5 = icmp ne i32 %a.10, %b
  call void @check1(i1 %cmp5)
  %cmp6 = icmp eq i32 %a.10, %b
  call void @check1(i1 %cmp6)
  ret void

else:
  ret void
}

define i1 @non_const_range_minmax(i8 %a, i8 %b) {
; CHECK-LABEL: @non_const_range_minmax(
; CHECK-NEXT:    [[A2:%.*]] = call i8 @llvm.umin.i8(i8 [[A:%.*]], i8 10)
; CHECK-NEXT:    [[B2:%.*]] = call i8 @llvm.umax.i8(i8 [[B:%.*]], i8 11)
; CHECK-NEXT:    ret i1 true
;
  %a2 = call i8 @llvm.umin.i8(i8 %a, i8 10)
  %b2 = call i8 @llvm.umax.i8(i8 %b, i8 11)
  %cmp1 = icmp ult i8 %a2, %b2
  ret i1 %cmp1
}

define <2 x i1> @non_const_range_minmax_vec(<2 x i8> %a, <2 x i8> %b) {
; CHECK-LABEL: @non_const_range_minmax_vec(
; CHECK-NEXT:    [[A2:%.*]] = call <2 x i8> @llvm.umin.v2i8(<2 x i8> [[A:%.*]], <2 x i8> <i8 10, i8 10>)
; CHECK-NEXT:    [[B2:%.*]] = call <2 x i8> @llvm.umax.v2i8(<2 x i8> [[B:%.*]], <2 x i8> <i8 11, i8 11>)
; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
;
  %a2 = call <2 x i8> @llvm.umin.v2i8(<2 x i8> %a, <2 x i8> <i8 10, i8 10>)
  %b2 = call <2 x i8> @llvm.umax.v2i8(<2 x i8> %b, <2 x i8> <i8 11, i8 11>)
  %cmp1 = icmp ult <2 x i8> %a2, %b2
  ret <2 x i1> %cmp1
}

define void @ashr_sgt(i8 %x) {
; CHECK-LABEL: @ashr_sgt(
; CHECK-NEXT:    [[S:%.*]] = ashr i8 [[X:%.*]], 2
; CHECK-NEXT:    [[C:%.*]] = icmp sgt i8 [[S]], 1
; CHECK-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    [[C3:%.*]] = icmp ugt i8 [[X]], 8
; CHECK-NEXT:    call void @check1(i1 [[C3]])
; CHECK-NEXT:    ret void
; CHECK:       else:
; CHECK-NEXT:    ret void
;
  %s = ashr i8 %x, 2
  %c = icmp sgt i8 %s, 1
  br i1 %c, label %if, label %else
if:
  %c2 = icmp sgt i8 %x, 7
  call void @check1(i1 %c2)
  %c3 = icmp sgt i8 %x, 8
  call void @check1(i1 %c3)
  ret void
else:
  ret void
}

define void @ashr_sge(i8 %x) {
; CHECK-LABEL: @ashr_sge(
; CHECK-NEXT:    [[S:%.*]] = ashr i8 [[X:%.*]], 2
; CHECK-NEXT:    [[C:%.*]] = icmp sge i8 [[S]], 1
; CHECK-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    [[C3:%.*]] = icmp uge i8 [[X]], 5
; CHECK-NEXT:    call void @check1(i1 [[C3]])
; CHECK-NEXT:    ret void
; CHECK:       else:
; CHECK-NEXT:    ret void
;
  %s = ashr i8 %x, 2
  %c = icmp sge i8 %s, 1
  br i1 %c, label %if, label %else
if:
  %c2 = icmp sge i8 %x, 4
  call void @check1(i1 %c2)
  %c3 = icmp sge i8 %x, 5
  call void @check1(i1 %c3)
  ret void
else:
  ret void
}

define void @ashr_slt(i8 %x) {
; CHECK-LABEL: @ashr_slt(
; CHECK-NEXT:    [[S:%.*]] = ashr i8 [[X:%.*]], 2
; CHECK-NEXT:    [[C:%.*]] = icmp slt i8 [[S]], 1
; CHECK-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    [[C3:%.*]] = icmp slt i8 [[X]], 3
; CHECK-NEXT:    call void @check1(i1 [[C3]])
; CHECK-NEXT:    ret void
; CHECK:       else:
; CHECK-NEXT:    ret void
;
  %s = ashr i8 %x, 2
  %c = icmp slt i8 %s, 1
  br i1 %c, label %if, label %else
if:
  %c2 = icmp slt i8 %x, 4
  call void @check1(i1 %c2)
  %c3 = icmp slt i8 %x, 3
  call void @check1(i1 %c3)
  ret void
else:
  ret void
}

define void @ashr_sle(i8 %x) {
; CHECK-LABEL: @ashr_sle(
; CHECK-NEXT:    [[S:%.*]] = ashr i8 [[X:%.*]], 2
; CHECK-NEXT:    [[C:%.*]] = icmp sle i8 [[S]], 1
; CHECK-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK:       if:
; CHECK-NEXT:    call void @check1(i1 true)
; CHECK-NEXT:    [[C3:%.*]] = icmp sle i8 [[X]], 6
; CHECK-NEXT:    call void @check1(i1 [[C3]])
; CHECK-NEXT:    ret void
; CHECK:       else:
; CHECK-NEXT:    ret void
;
  %s = ashr i8 %x, 2
  %c = icmp sle i8 %s, 1
  br i1 %c, label %if, label %else
if:
  %c2 = icmp sle i8 %x, 7
  call void @check1(i1 %c2)
  %c3 = icmp sle i8 %x, 6
  call void @check1(i1 %c3)
  ret void
else:
  ret void
}

declare i8 @llvm.umin.i8(i8, i8)
declare i8 @llvm.umax.i8(i8, i8)
declare <2 x i8> @llvm.umin.v2i8(<2 x i8>, <2 x i8>)
declare <2 x i8> @llvm.umax.v2i8(<2 x i8>, <2 x i8>)

attributes #4 = { noreturn }

define i1 @pr69928(i64 noundef %arg, i64 noundef %arg1) {
; CHECK-LABEL: @pr69928(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i64 [[ARG:%.*]], 64424509440
; CHECK-NEXT:    [[AND:%.*]] = and i64 [[ARG1:%.*]], 4294967295
; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i64 [[ARG]], [[AND]]
; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false
; CHECK-NEXT:    ret i1 [[SELECT]]
;
entry:
  %cmp1 = icmp ult i64 %arg, 64424509440
  %and = and i64 %arg1, 4294967295
  %cmp2 = icmp slt i64 %arg, %and
  %select = select i1 %cmp1, i1 %cmp2, i1 false
  ret i1 %select
}

define i1 @test_select_flip(i64 noundef %arg) {
; CHECK-LABEL: @test_select_flip(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i64 [[ARG:%.*]], 1000
; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i64 [[ARG]], 100
; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false
; CHECK-NEXT:    ret i1 [[SELECT]]
;
entry:
  %cmp1 = icmp ult i64 %arg, 1000
  %cmp2 = icmp slt i64 %arg, 100
  %select = select i1 %cmp1, i1 %cmp2, i1 false
  ret i1 %select
}

define i1 @test_select_flip_fail1(i64 noundef %arg) {
; CHECK-LABEL: @test_select_flip_fail1(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i64 [[ARG:%.*]], 1000
; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[ARG]], 100
; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false
; CHECK-NEXT:    ret i1 [[SELECT]]
;
entry:
  %cmp1 = icmp slt i64 %arg, 1000
  %cmp2 = icmp slt i64 %arg, 100
  %select = select i1 %cmp1, i1 %cmp2, i1 false
  ret i1 %select
}

define i1 @test_select_flip_fail2(i64 noundef %arg) {
; CHECK-LABEL: @test_select_flip_fail2(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i64 [[ARG:%.*]], 1000
; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[ARG]], 100
; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[CMP1]], i1 false, i1 [[CMP2]]
; CHECK-NEXT:    ret i1 [[SELECT]]
;
entry:
  %cmp1 = icmp ult i64 %arg, 1000
  %cmp2 = icmp slt i64 %arg, 100
  %select = select i1 %cmp1, i1 false, i1 %cmp2
  ret i1 %select
}

define i1 @test_select_flip_fail3(i64 noundef %arg, i64 noundef %arg1) {
; CHECK-LABEL: @test_select_flip_fail3(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i64 [[ARG1:%.*]], 1000
; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[ARG:%.*]], 100
; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false
; CHECK-NEXT:    ret i1 [[SELECT]]
;
entry:
  %cmp1 = icmp ult i64 %arg1, 1000
  %cmp2 = icmp slt i64 %arg, 100
  %select = select i1 %cmp1, i1 %cmp2, i1 false
  ret i1 %select
}

define i1 @test_select_flip_fail4(i64 noundef %arg) {
; CHECK-LABEL: @test_select_flip_fail4(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[ARG:%.*]], 100
; CHECK-NEXT:    [[SELECT:%.*]] = select i1 true, i1 [[CMP2]], i1 false
; CHECK-NEXT:    ret i1 [[SELECT]]
;
entry:
  %cmp2 = icmp slt i64 %arg, 100
  %select = select i1 true, i1 %cmp2, i1 false
  ret i1 %select
}

define i1 @test_select_flip_fail5(i64 noundef %arg, i64 noundef %arg1) {
; CHECK-LABEL: @test_select_flip_fail5(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i64 [[ARG:%.*]], 1000
; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[ARG]], [[ARG1:%.*]]
; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false
; CHECK-NEXT:    ret i1 [[SELECT]]
;
entry:
  %cmp1 = icmp ult i64 %arg, 1000
  %cmp2 = icmp slt i64 %arg, %arg1
  %select = select i1 %cmp1, i1 %cmp2, i1 false
  ret i1 %select
}

declare void @opaque()

define void @test_icmp_ne_from_implied_range(i32 noundef %arg) {
; CHECK-LABEL: @test_icmp_ne_from_implied_range(
; CHECK-NEXT:    [[AND_MASK:%.*]] = and i32 [[ARG:%.*]], -8
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND_MASK]], -16
; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[ELSE:%.*]]
; CHECK:       else:
; CHECK-NEXT:    br label [[END]]
; CHECK:       sw.case:
; CHECK-NEXT:    call void @opaque()
; CHECK-NEXT:    br label [[END]]
; CHECK:       end:
; CHECK-NEXT:    ret void
;
  %and.mask = and i32 %arg, -8
  %cmp = icmp eq i32 %and.mask, -16
  br i1 %cmp, label %end, label %else

else:
  ; %arg is within [-8, -16).
  switch i32 %arg, label %end [
  i32 -16, label %sw.case
  i32 -12, label %sw.case
  i32 -9, label %sw.case
  ]

sw.case:
  call void @opaque()
  br label %end

end:
  ; %arg is within [-16, -8).
  ret void
}