; 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()