blob: a72b5e0bbfa03813fccf7c729e5e20a87b1e95ec [file] [log] [blame]
; 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
}
define i1 @or_nonzero_from_nonequal(i8 %x, i8 %y) {
; CHECK-LABEL: @or_nonzero_from_nonequal(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
; CHECK: if.then:
; CHECK-NEXT: ret i1 false
; CHECK: if.else:
; CHECK-NEXT: ret i1 false
;
entry:
%cond = icmp eq i8 %x, %y
br i1 %cond, label %if.else, label %if.then
if.then:
%or = or i8 %x, %y
%cmp = icmp eq i8 %or, 0
ret i1 %cmp
if.else:
ret i1 false
}
define i1 @test_nonequal_domcond1(i64 %x, i64 %y, i64 %z, i64 %w) {
; CHECK-LABEL: @test_nonequal_domcond1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND1:%.*]] = icmp eq i64 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[W:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[COND1]], i1 true, i1 [[COND2]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
; CHECK: if.then:
; CHECK-NEXT: ret i1 false
; CHECK: if.end:
; CHECK-NEXT: ret i1 false
;
entry:
%cond1 = icmp eq i64 %y, %x
%cond2 = icmp eq i64 %w, %z
%or.cond = select i1 %cond1, i1 true, i1 %cond2
br i1 %or.cond, label %if.end, label %if.then
if.then:
%sub1 = sub i64 %w, %z
%sub2 = sub i64 %y, %x
%umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
%cmp = icmp eq i64 %umin, 0
ret i1 %cmp
if.end:
ret i1 false
}
define i1 @test_nonequal_domcond2(i64 %x, i64 %y, i64 %z, i64 %w) {
; CHECK-LABEL: @test_nonequal_domcond2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND1:%.*]] = icmp ne i64 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[COND2:%.*]] = icmp ne i64 [[W:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[COND1]], i1 [[COND2]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: ret i1 false
; CHECK: if.end:
; CHECK-NEXT: ret i1 false
;
entry:
%cond1 = icmp ne i64 %y, %x
%cond2 = icmp ne i64 %w, %z
%or.cond = select i1 %cond1, i1 %cond2, i1 false
br i1 %or.cond, label %if.then, label %if.end
if.then:
%sub1 = sub i64 %w, %z
%sub2 = sub i64 %y, %x
%umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
%cmp = icmp eq i64 %umin, 0
ret i1 %cmp
if.end:
ret i1 false
}
define i1 @test_nonequal_assume(i64 %x, i64 %y, i64 %z, i64 %w) {
; CHECK-LABEL: @test_nonequal_assume(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND1:%.*]] = icmp ne i64 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: call void @llvm.assume(i1 [[COND1]])
; CHECK-NEXT: [[COND2:%.*]] = icmp ne i64 [[W:%.*]], [[Z:%.*]]
; CHECK-NEXT: call void @llvm.assume(i1 [[COND2]])
; CHECK-NEXT: ret i1 false
;
entry:
%cond1 = icmp ne i64 %y, %x
call void @llvm.assume(i1 %cond1)
%cond2 = icmp ne i64 %w, %z
call void @llvm.assume(i1 %cond2)
%sub1 = sub i64 %w, %z
%sub2 = sub i64 %y, %x
%umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
%cmp = icmp eq i64 %umin, 0
ret i1 %cmp
}
; Negative tests
define i1 @test_nonequal_invalid_domcond1(i64 %x, i64 %y, i64 %z, i64 %w) {
; CHECK-LABEL: @test_nonequal_invalid_domcond1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND1:%.*]] = icmp ne i64 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[W:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[COND1]], i1 true, i1 [[COND2]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
; CHECK: if.then:
; CHECK-NEXT: ret i1 true
; CHECK: if.end:
; CHECK-NEXT: ret i1 false
;
entry:
%cond1 = icmp ne i64 %y, %x
%cond2 = icmp eq i64 %w, %z
%or.cond = select i1 %cond1, i1 true, i1 %cond2
br i1 %or.cond, label %if.end, label %if.then
if.then:
%sub1 = sub i64 %w, %z
%sub2 = sub i64 %y, %x
%umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
%cmp = icmp eq i64 %umin, 0
ret i1 %cmp
if.end:
ret i1 false
}
define i1 @test_nonequal_invalid_domcond2(i64 %x, i64 %y, i64 %z, i64 %w) {
; CHECK-LABEL: @test_nonequal_invalid_domcond2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND1:%.*]] = icmp eq i64 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[W:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[COND1]], i1 true, i1 [[COND2]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[SUB1:%.*]] = sub i64 [[W]], [[Z]]
; CHECK-NEXT: [[SUB2:%.*]] = sub i64 [[Y]], [[X]]
; CHECK-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[SUB1]], i64 [[SUB2]])
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[UMIN]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
entry:
%cond1 = icmp eq i64 %y, %x
%cond2 = icmp eq i64 %w, %z
%or.cond = select i1 %cond1, i1 true, i1 %cond2
br i1 %or.cond, label %if.then, label %if.end
if.then:
br label %if.end
if.end:
%sub1 = sub i64 %w, %z
%sub2 = sub i64 %y, %x
%umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
%cmp = icmp eq i64 %umin, 0
ret i1 %cmp
}
define i1 @test_nonequal_invalid_assume(i64 %x, i64 %y, i64 %z, i64 %w) {
; CHECK-LABEL: @test_nonequal_invalid_assume(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SUB1:%.*]] = sub i64 [[W:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[SUB2:%.*]] = sub i64 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[SUB1]], i64 [[SUB2]])
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[UMIN]], 0
; CHECK-NEXT: call void @side_effect()
; CHECK-NEXT: [[COND1:%.*]] = icmp ne i64 [[Y]], [[X]]
; CHECK-NEXT: call void @llvm.assume(i1 [[COND1]])
; CHECK-NEXT: [[COND2:%.*]] = icmp ne i64 [[W]], [[Z]]
; CHECK-NEXT: call void @llvm.assume(i1 [[COND2]])
; CHECK-NEXT: ret i1 [[CMP]]
;
entry:
%sub1 = sub i64 %w, %z
%sub2 = sub i64 %y, %x
%umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
%cmp = icmp eq i64 %umin, 0
call void @side_effect()
%cond1 = icmp ne i64 %y, %x
call void @llvm.assume(i1 %cond1)
%cond2 = icmp ne i64 %w, %z
call void @llvm.assume(i1 %cond2)
ret i1 %cmp
}
; TODO: We can prove `%cond2` is always false
define void @test_nonequal_domcond_loop1(i32 %x0, i1 %x1) {
; CHECK-LABEL: @test_nonequal_domcond_loop1(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
; CHECK: loop.header:
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[X0:%.*]], [[LATCH:%.*]] ]
; CHECK-NEXT: br label [[LATCH]]
; CHECK: latch:
; CHECK-NEXT: br i1 [[X1:%.*]], label [[IF_THEN:%.*]], label [[LOOP_HEADER]]
; CHECK: if.then:
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X0]], 1
; CHECK-NEXT: [[COND1:%.*]] = icmp eq i32 [[AND]], [[PHI]]
; CHECK-NEXT: br i1 [[COND1]], label [[IF_THEN2:%.*]], label [[LATCH]]
; CHECK: if.then2:
; CHECK-NEXT: br label [[BB:%.*]]
; CHECK: indirectbb:
; CHECK-NEXT: [[COND2:%.*]] = icmp eq i32 [[PHI]], 31
; CHECK-NEXT: br i1 [[COND2]], label [[EXIT:%.*]], label [[LATCH]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop.header
loop.header:
%phi = phi i32 [ 0, %entry ], [ %x0, %latch ]
br label %latch
latch:
br i1 %x1, label %if.then, label %loop.header
if.then:
%and = and i32 %x0, 1
%cond1 = icmp eq i32 %and, %phi
br i1 %cond1, label %if.then2, label %latch
if.then2:
br label %indirectbb
indirectbb:
%cond2 = icmp eq i32 %phi, 31
br i1 %cond2, label %exit, label %latch
exit:
ret void
}
define void @test_nonequal_domcond_loop2(ptr %p) {
; CHECK-LABEL: @test_nonequal_domcond_loop2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[LOAD1:%.*]] = load volatile i8, ptr [[P:%.*]], align 1
; CHECK-NEXT: br label [[WHILE_COND:%.*]]
; CHECK: while.cond:
; CHECK-NEXT: [[LOAD2:%.*]] = load volatile i8, ptr [[P]], align 1
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[LOAD2]], 0
; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 [[LOAD2]], [[LOAD1]]
; CHECK-NEXT: [[OR:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP2]]
; CHECK-NEXT: br i1 [[OR]], label [[WHILE_COND]], label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: br i1 false, label [[WHILE_COND]], label [[FOR_BODY]]
;
entry:
%load1 = load volatile i8, ptr %p, align 1
br label %while.cond
while.cond:
%load2 = load volatile i8, ptr %p, align 1
%cmp1 = icmp eq i8 %load2, 0
%cmp2 = icmp uge i8 %load2, %load1
%or = select i1 %cmp1, i1 true, i1 %cmp2
br i1 %or, label %while.cond, label %for.body
for.body:
%cond = icmp eq i8 %load1, %load2
br i1 %cond, label %while.cond, label %for.body
}
declare void @side_effect()