; RUN: opt -jump-threading -S < %s | FileCheck %s

declare void @side_effect(i32)

define void @test0(i32 %i, i32 %len) {
; CHECK-LABEL: @test0(
 entry:
  call void @side_effect(i32 0)
  %i.inc = add nuw i32 %i, 1
  %c0 = icmp ult i32 %i.inc, %len
  br i1 %c0, label %left, label %right

 left:
; CHECK: entry:
; CHECK: br i1 %c0, label %left0, label %right

; CHECK: left0:
; CHECK: call void @side_effect
; CHECK-NOT: br i1 %c1
; CHECK: call void @side_effect
  call void @side_effect(i32 0)
  %c1 = icmp ult i32 %i, %len
  br i1 %c1, label %left0, label %right

 left0:
  call void @side_effect(i32 0)
  ret void

 right:
  %t = phi i32 [ 1, %left ], [ 2, %entry ]
  call void @side_effect(i32 %t)
  ret void
}

define void @test1(i32 %i, i32 %len) {
; CHECK-LABEL: @test1(
 entry:
  call void @side_effect(i32 0)
  %i.inc = add nsw i32 %i, 1
  %c0 = icmp slt i32 %i.inc, %len
  br i1 %c0, label %left, label %right

 left:
; CHECK: entry:
; CHECK: br i1 %c0, label %left0, label %right

; CHECK: left0:
; CHECK: call void @side_effect
; CHECK-NOT: br i1 %c1
; CHECK: call void @side_effect
  call void @side_effect(i32 0)
  %c1 = icmp slt i32 %i, %len
  br i1 %c1, label %left0, label %right

 left0:
  call void @side_effect(i32 0)
  ret void

 right:
  %t = phi i32 [ 1, %left ], [ 2, %entry ]
  call void @side_effect(i32 %t)
  ret void
}

define void @test2(i32 %i, i32 %len, i1* %c.ptr) {
; CHECK-LABEL: @test2(

; CHECK: entry:
; CHECK: br i1 %c0, label %cont, label %right
; CHECK: cont:
; CHECK: br i1 %c, label %left0, label %right
; CHECK: left0:
; CHECK: call void @side_effect(i32 0)
; CHECK: call void @side_effect(i32 0)
 entry:
  call void @side_effect(i32 0)
  %i.inc = add nsw i32 %i, 1
  %c0 = icmp slt i32 %i.inc, %len
  br i1 %c0, label %cont, label %right

 cont:
  %c = load i1, i1* %c.ptr
  br i1 %c, label %left, label %right

 left:
  call void @side_effect(i32 0)
  %c1 = icmp slt i32 %i, %len
  br i1 %c1, label %left0, label %right

 left0:
  call void @side_effect(i32 0)
  ret void

 right:
  %t = phi i32 [ 1, %left ], [ 2, %entry ], [ 3, %cont ]
  call void @side_effect(i32 %t)
  ret void
}

; A s<= B implies A s> B is false.
; CHECK-LABEL: @test3(
; CHECK: entry:
; CHECK: br i1 %cmp, label %if.end, label %if.end3
; CHECK-NOT: br i1 %cmp1, label %if.then2, label %if.end
; CHECK-NOT: call void @side_effect(i32 0)
; CHECK: br label %if.end3
; CHECK: ret void

define void @test3(i32 %a, i32 %b) {
entry:
  %cmp = icmp sle i32 %a, %b
  br i1 %cmp, label %if.then, label %if.end3

if.then:
  %cmp1 = icmp sgt i32 %a, %b
  br i1 %cmp1, label %if.then2, label %if.end

if.then2:
  call void @side_effect(i32 0)
  br label %if.end

if.end:
  br label %if.end3

if.end3:
  ret void
}

declare void @is(i1)

; If A >=s B is false then A <=s B is implied true.
; CHECK-LABEL: @test_sge_sle
; CHECK: call void @is(i1 true)
; CHECK-NOT: call void @is(i1 false)
define void @test_sge_sle(i32 %a, i32 %b) {
  %cmp1 = icmp sge i32 %a, %b
  br i1 %cmp1, label %untaken, label %taken

taken:
  %cmp2 = icmp sle i32 %a, %b
  br i1 %cmp2, label %istrue, label %isfalse

istrue:
  call void @is(i1 true)
  ret void

isfalse:
  call void @is(i1 false)
  ret void

untaken:
  ret void
}

; If A <=s B is false then A <=s B is implied false.
; CHECK-LABEL: @test_sle_sle
; CHECK-NOT: call void @is(i1 true)
; CHECK: call void @is(i1 false)
define void @test_sle_sle(i32 %a, i32 %b) {
  %cmp1 = icmp sle i32 %a, %b
  br i1 %cmp1, label %untaken, label %taken

taken:
  %cmp2 = icmp sle i32 %a, %b
  br i1 %cmp2, label %istrue, label %isfalse

istrue:
  call void @is(i1 true)
  ret void

isfalse:
  call void @is(i1 false)
  ret void

untaken:
  ret void
}
