llvm/llvm/test/Transforms/InstCombine/icmp-dom.ll

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

define void @idom_sign_bit_check_edge_dominates(i64 %a) {
; CHECK-LABEL: @idom_sign_bit_check_edge_dominates(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[A:%.*]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[LOR_RHS:%.*]]
; CHECK:       land.lhs.true:
; CHECK-NEXT:    br label [[LOR_END:%.*]]
; CHECK:       lor.rhs:
; CHECK-NEXT:    [[CMP2_NOT:%.*]] = icmp eq i64 [[A]], 0
; CHECK-NEXT:    br i1 [[CMP2_NOT]], label [[LOR_END]], label [[LAND_RHS:%.*]]
; CHECK:       land.rhs:
; CHECK-NEXT:    br label [[LOR_END]]
; CHECK:       lor.end:
; CHECK-NEXT:    ret void
;
entry:
  %cmp = icmp slt i64 %a, 0
  br i1 %cmp, label %land.lhs.true, label %lor.rhs

land.lhs.true:
  br label %lor.end

lor.rhs:
  %cmp2 = icmp sgt i64 %a, 0
  br i1 %cmp2, label %land.rhs, label %lor.end

land.rhs:
  br label %lor.end

lor.end:
  ret void
}

define void @idom_sign_bit_check_edge_not_dominates(i64 %a, i1 %c1) {
; CHECK-LABEL: @idom_sign_bit_check_edge_not_dominates(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[A:%.*]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[LOR_RHS:%.*]]
; CHECK:       land.lhs.true:
; CHECK-NEXT:    br i1 [[C1:%.*]], label [[LOR_END:%.*]], label [[LOR_RHS]]
; CHECK:       lor.rhs:
; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i64 [[A]], 0
; CHECK-NEXT:    br i1 [[CMP2]], label [[LAND_RHS:%.*]], label [[LOR_END]]
; CHECK:       land.rhs:
; CHECK-NEXT:    br label [[LOR_END]]
; CHECK:       lor.end:
; CHECK-NEXT:    ret void
;
entry:
  %cmp = icmp slt i64 %a, 0
  br i1 %cmp, label %land.lhs.true, label %lor.rhs

land.lhs.true:
  br i1 %c1, label %lor.end, label %lor.rhs

lor.rhs:
  %cmp2 = icmp sgt i64 %a, 0
  br i1 %cmp2, label %land.rhs, label %lor.end

land.rhs:
  br label %lor.end

lor.end:
  ret void
}

define void @idom_sign_bit_check_edge_dominates_select(i64 %a, i64 %b) {
; CHECK-LABEL: @idom_sign_bit_check_edge_dominates_select(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[A:%.*]], 5
; CHECK-NEXT:    br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[LOR_RHS:%.*]]
; CHECK:       land.lhs.true:
; CHECK-NEXT:    br label [[LOR_END:%.*]]
; CHECK:       lor.rhs:
; CHECK-NEXT:    [[CMP3_NOT:%.*]] = icmp eq i64 [[A]], [[B:%.*]]
; CHECK-NEXT:    br i1 [[CMP3_NOT]], label [[LOR_END]], label [[LAND_RHS:%.*]]
; CHECK:       land.rhs:
; CHECK-NEXT:    br label [[LOR_END]]
; CHECK:       lor.end:
; CHECK-NEXT:    ret void
;
entry:
  %cmp = icmp slt i64 %a, 5
  br i1 %cmp, label %land.lhs.true, label %lor.rhs

land.lhs.true:
  br label %lor.end

lor.rhs:
  %cmp2 = icmp sgt i64 %a, 5
  %select = select i1 %cmp2, i64 %a, i64 5
  %cmp3 = icmp ne i64 %select, %b
  br i1 %cmp3, label %land.rhs, label %lor.end

land.rhs:
  br label %lor.end

lor.end:
  ret void
}

define void @idom_zbranch(i64 %a) {
; CHECK-LABEL: @idom_zbranch(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i64 [[A:%.*]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[LOR_END:%.*]], label [[LOR_RHS:%.*]]
; CHECK:       lor.rhs:
; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[A]], 0
; CHECK-NEXT:    br i1 [[CMP2]], label [[LAND_RHS:%.*]], label [[LOR_END]]
; CHECK:       land.rhs:
; CHECK-NEXT:    br label [[LOR_END]]
; CHECK:       lor.end:
; CHECK-NEXT:    ret void
;
entry:
  %cmp = icmp sgt i64 %a, 0
  br i1 %cmp, label %lor.end, label %lor.rhs

lor.rhs:
  %cmp2 = icmp slt i64 %a, 0
  br i1 %cmp2, label %land.rhs, label %lor.end

land.rhs:
  br label %lor.end

lor.end:
  ret void
}

define void @idom_not_zbranch(i32 %a, i32 %b) {
; CHECK-LABEL: @idom_not_zbranch(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[RETURN:%.*]], label [[IF_END:%.*]]
; CHECK:       if.end:
; CHECK-NEXT:    [[CMP2_NOT:%.*]] = icmp eq i32 [[A]], [[B:%.*]]
; CHECK-NEXT:    br i1 [[CMP2_NOT]], label [[RETURN]], label [[IF_THEN3:%.*]]
; CHECK:       if.then3:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       return:
; CHECK-NEXT:    ret void
;
entry:
  %cmp = icmp sgt i32 %a, 0
  br i1 %cmp, label %return, label %if.end

if.end:
  %cmp1 = icmp slt i32 %a, 0
  %a. = select i1 %cmp1, i32 %a, i32 0
  %cmp2 = icmp ne i32 %a., %b
  br i1 %cmp2, label %if.then3, label %return

if.then3:
  br label %return

return:
  ret void
}

define void @trueblock_cmp_eq(i32 %a, i32 %b) {
; CHECK-LABEL: @trueblock_cmp_eq(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[IF_END:%.*]], label [[RETURN:%.*]]
; CHECK:       if.end:
; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[A]], 1
; CHECK-NEXT:    br i1 [[CMP1]], label [[IF_THEN3:%.*]], label [[RETURN]]
; CHECK:       if.then3:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       return:
; CHECK-NEXT:    ret void
;
entry:
  %cmp = icmp sgt i32 %a, 0
  br i1 %cmp, label %if.end, label %return

if.end:
  %cmp1 = icmp slt i32 %a, 2
  br i1 %cmp1, label %if.then3, label %return

if.then3:
  br label %return

return:
  ret void
}

define i1 @trueblock_cmp_is_false(i32 %x, i32 %y) {
; CHECK-LABEL: @trueblock_cmp_is_false(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
; CHECK:       t:
; CHECK-NEXT:    ret i1 false
; CHECK:       f:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = icmp sgt i32 %x, %y
  br i1 %cmp, label %t, label %f
t:
  %cmp2 = icmp slt i32 %x, %y
  ret i1 %cmp2
f:
  ret i1 %cmp
}

define i1 @trueblock_cmp_is_false_commute(i32 %x, i32 %y) {
; CHECK-LABEL: @trueblock_cmp_is_false_commute(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
; CHECK:       t:
; CHECK-NEXT:    ret i1 false
; CHECK:       f:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = icmp eq i32 %x, %y
  br i1 %cmp, label %t, label %f
t:
  %cmp2 = icmp sgt i32 %y, %x
  ret i1 %cmp2
f:
  ret i1 %cmp
}

define i1 @trueblock_cmp_is_true(i32 %x, i32 %y) {
; CHECK-LABEL: @trueblock_cmp_is_true(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
; CHECK:       t:
; CHECK-NEXT:    ret i1 true
; CHECK:       f:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = icmp ult i32 %x, %y
  br i1 %cmp, label %t, label %f
t:
  %cmp2 = icmp ne i32 %x, %y
  ret i1 %cmp2
f:
  ret i1 %cmp
}

define i1 @trueblock_cmp_is_true_commute(i32 %x, i32 %y) {
; CHECK-LABEL: @trueblock_cmp_is_true_commute(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
; CHECK:       t:
; CHECK-NEXT:    ret i1 true
; CHECK:       f:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = icmp ugt i32 %x, %y
  br i1 %cmp, label %t, label %f
t:
  %cmp2 = icmp ne i32 %y, %x
  ret i1 %cmp2
f:
  ret i1 %cmp
}

define i1 @falseblock_cmp_is_false(i32 %x, i32 %y) {
; CHECK-LABEL: @falseblock_cmp_is_false(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP_NOT:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    br i1 [[CMP_NOT]], label [[F:%.*]], label [[T:%.*]]
; CHECK:       t:
; CHECK-NEXT:    ret i1 true
; CHECK:       f:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = icmp sle i32 %x, %y
  br i1 %cmp, label %t, label %f
t:
  ret i1 %cmp
f:
  %cmp2 = icmp slt i32 %x, %y
  ret i1 %cmp2
}

define i1 @falseblock_cmp_is_false_commute(i32 %x, i32 %y) {
; CHECK-LABEL: @falseblock_cmp_is_false_commute(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
; CHECK:       t:
; CHECK-NEXT:    ret i1 true
; CHECK:       f:
; CHECK-NEXT:    ret i1 false
;
entry:
  %cmp = icmp eq i32 %x, %y
  br i1 %cmp, label %t, label %f
t:
  ret i1 %cmp
f:
  %cmp2 = icmp eq i32 %y, %x
  ret i1 %cmp2
}

define i1 @falseblock_cmp_is_true(i32 %x, i32 %y) {
; CHECK-LABEL: @falseblock_cmp_is_true(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
; CHECK:       t:
; CHECK-NEXT:    ret i1 true
; CHECK:       f:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = icmp ult i32 %x, %y
  br i1 %cmp, label %t, label %f
t:
  ret i1 %cmp
f:
  %cmp2 = icmp uge i32 %x, %y
  ret i1 %cmp2
}

define i1 @falseblock_cmp_is_true_commute(i32 %x, i32 %y) {
; CHECK-LABEL: @falseblock_cmp_is_true_commute(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
; CHECK:       t:
; CHECK-NEXT:    ret i1 true
; CHECK:       f:
; CHECK-NEXT:    ret i1 true
;
entry:
  %cmp = icmp sgt i32 %x, %y
  br i1 %cmp, label %t, label %f
t:
  ret i1 %cmp
f:
  %cmp2 = icmp sge i32 %y, %x
  ret i1 %cmp2
}

; This used to infinite loop because of a conflict
; with min/max canonicalization.

define i32 @PR48900(i32 %i, ptr %p) {
; CHECK-LABEL: @PR48900(
; CHECK-NEXT:    [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[I:%.*]], i32 1)
; CHECK-NEXT:    [[I4:%.*]] = icmp sgt i32 [[UMAX]], 0
; CHECK-NEXT:    br i1 [[I4]], label [[TRUELABEL:%.*]], label [[FALSELABEL:%.*]]
; CHECK:       truelabel:
; CHECK-NEXT:    [[SMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[UMAX]], i32 2)
; CHECK-NEXT:    ret i32 [[SMIN]]
; CHECK:       falselabel:
; CHECK-NEXT:    ret i32 0
;
  %maxcmp = icmp ugt i32 %i, 1
  %umax = select i1 %maxcmp, i32 %i, i32 1
  %i4 = icmp sgt i32 %umax, 0
  br i1 %i4, label %truelabel, label %falselabel

truelabel:
  %mincmp = icmp ult i32 %umax, 2
  %smin = select i1 %mincmp, i32 %umax, i32 2
  ret i32 %smin

falselabel:
  ret i32 0
}

; This used to infinite loop because of a conflict
; with min/max canonicalization.

define i8 @PR48900_alt(i8 %i, ptr %p) {
; CHECK-LABEL: @PR48900_alt(
; CHECK-NEXT:    [[SMAX:%.*]] = call i8 @llvm.smax.i8(i8 [[I:%.*]], i8 -127)
; CHECK-NEXT:    [[I4:%.*]] = icmp ugt i8 [[SMAX]], -128
; CHECK-NEXT:    br i1 [[I4]], label [[TRUELABEL:%.*]], label [[FALSELABEL:%.*]]
; CHECK:       truelabel:
; CHECK-NEXT:    [[UMIN:%.*]] = call i8 @llvm.smin.i8(i8 [[SMAX]], i8 -126)
; CHECK-NEXT:    ret i8 [[UMIN]]
; CHECK:       falselabel:
; CHECK-NEXT:    ret i8 0
;
  %maxcmp = icmp sgt i8 %i, -127
  %smax = select i1 %maxcmp, i8 %i, i8 -127
  %i4 = icmp ugt i8 %smax, 128
  br i1 %i4, label %truelabel, label %falselabel

truelabel:
  %mincmp = icmp slt i8 %smax, -126
  %umin = select i1 %mincmp, i8 %smax, i8 -126
  ret i8 %umin

falselabel:
  ret i8 0
}

define i1 @and_mask1_eq(i32 %conv) {
; CHECK-LABEL: @and_mask1_eq(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[CONV:%.*]], 1
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK:       then:
; CHECK-NEXT:    ret i1 false
; CHECK:       else:
; CHECK-NEXT:    ret i1 false
;
entry:
  %and = and i32 %conv, 1
  %cmp = icmp eq i32 %and, 0
  br i1 %cmp, label %then, label %else

then:
  ret i1 0

else:
  %and1 = and i32 %conv, 3
  %cmp1 = icmp eq i32 %and1, 0
  ret i1 %cmp1
}

define i1 @and_mask1_ne(i32 %conv) {
; CHECK-LABEL: @and_mask1_ne(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[CONV:%.*]], 1
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK:       then:
; CHECK-NEXT:    ret i1 false
; CHECK:       else:
; CHECK-NEXT:    ret i1 true
;
entry:
  %and = and i32 %conv, 1
  %cmp = icmp eq i32 %and, 0
  br i1 %cmp, label %then, label %else

then:
  ret i1 0

else:
  %and1 = and i32 %conv, 3
  %cmp1 = icmp ne i32 %and1, 0
  ret i1 %cmp1
}

define i1 @and_mask2(i32 %conv) {
; CHECK-LABEL: @and_mask2(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[CONV:%.*]], 4
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK:       then:
; CHECK-NEXT:    ret i1 false
; CHECK:       else:
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[CONV]], 3
; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[AND1]], 0
; CHECK-NEXT:    ret i1 [[CMP1]]
;
entry:
  %and = and i32 %conv, 4
  %cmp = icmp eq i32 %and, 0
  br i1 %cmp, label %then, label %else

then:
  ret i1 0

else:
  %and1 = and i32 %conv, 3
  %cmp1 = icmp eq i32 %and1, 0
  ret i1 %cmp1
}

; TODO: %cmp1 can be folded into false.

define i1 @and_mask3(i32 %conv) {
; CHECK-LABEL: @and_mask3(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[CONV:%.*]], 3
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK:       then:
; CHECK-NEXT:    ret i1 false
; CHECK:       else:
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[CONV]], 7
; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[AND1]], 0
; CHECK-NEXT:    ret i1 [[CMP1]]
;
entry:
  %and = and i32 %conv, 3
  %cmp = icmp eq i32 %and, 0
  br i1 %cmp, label %then, label %else

then:
  ret i1 0

else:
  %and1 = and i32 %conv, 7
  %cmp1 = icmp eq i32 %and1, 0
  ret i1 %cmp1
}

define i1 @and_mask4(i32 %conv) {
; CHECK-LABEL: @and_mask4(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[CONV:%.*]], 4
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK:       then:
; CHECK-NEXT:    ret i1 false
; CHECK:       else:
; CHECK-NEXT:    ret i1 false
;
entry:
  %and = and i32 %conv, 4
  %cmp = icmp eq i32 %and, 0
  br i1 %cmp, label %then, label %else

then:
  ret i1 0

else:
  %and1 = and i32 %conv, 7
  %cmp1 = icmp eq i32 %and1, 0
  ret i1 %cmp1
}