; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
; Tests for foldAndOrOfICmpEqConstantAndICmp
; https://github.com/llvm/llvm-project/issues/63749
; ==============================================================================
; (icmp eq X, C) | (icmp ult Other, (X - C)) -> (icmp ule Other, (X - (C + 1)))
; (icmp ne X, C) & (icmp uge Other, (X - C)) -> (icmp ugt Other, (X - (C + 1)))
; ==============================================================================
; ==============================================================================
; Basic tests
; ==============================================================================
define i1 @eq_basic(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @eq_basic(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X]], -1
; CHECK-NEXT: [[OR:%.*]] = icmp uge i8 [[TMP1]], [[Y]]
; CHECK-NEXT: ret i1 [[OR]]
;
%c1 = icmp eq i8 %x, 0
%c2 = icmp ugt i8 %x, %y
%or = or i1 %c1, %c2
ret i1 %or
}
define i1 @ne_basic_equal_5(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @ne_basic_equal_5(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X]], -6
; CHECK-NEXT: [[AND:%.*]] = icmp ult i8 [[TMP1]], [[Y]]
; CHECK-NEXT: ret i1 [[AND]]
;
%sub = add i8 %x, -5
%c1 = icmp ne i8 %x, 5
%c2 = icmp ule i8 %sub, %y
%and = and i1 %c1, %c2
ret i1 %and
}
define i1 @eq_basic_equal_minus_1(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @eq_basic_equal_minus_1(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[OR:%.*]] = icmp uge i8 [[X]], [[Y]]
; CHECK-NEXT: ret i1 [[OR]]
;
%add = add i8 %x, 1
%c1 = icmp eq i8 %x, -1
%c2 = icmp ugt i8 %add, %y
%or = or i1 %c1, %c2
ret i1 %or
}
define i1 @ne_basic_equal_minus_7(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @ne_basic_equal_minus_7(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X]], 6
; CHECK-NEXT: [[AND:%.*]] = icmp ult i8 [[TMP1]], [[Y]]
; CHECK-NEXT: ret i1 [[AND]]
;
%add = add i8 %x, 7
%c1 = icmp ne i8 %x, -7
%c2 = icmp ule i8 %add, %y
%and = and i1 %c1, %c2
ret i1 %and
}
define i1 @eq_basic_unequal(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @eq_basic_unequal(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[SUB:%.*]] = add i8 [[X]], -5
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[X]], 6
; CHECK-NEXT: [[C2:%.*]] = icmp ugt i8 [[SUB]], [[Y]]
; CHECK-NEXT: [[OR:%.*]] = or i1 [[C1]], [[C2]]
; CHECK-NEXT: ret i1 [[OR]]
;
%sub = add i8 %x, -5
%c1 = icmp eq i8 %x, 6
%c2 = icmp ugt i8 %sub, %y
%or = or i1 %c1, %c2
ret i1 %or
}
define i1 @ne_basic_unequal(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @ne_basic_unequal(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], 7
; CHECK-NEXT: [[C1:%.*]] = icmp ne i8 [[X]], -4
; CHECK-NEXT: [[C2:%.*]] = icmp ule i8 [[ADD]], [[Y]]
; CHECK-NEXT: [[AND:%.*]] = and i1 [[C1]], [[C2]]
; CHECK-NEXT: ret i1 [[AND]]
;
%add = add i8 %x, 7
%c1 = icmp ne i8 %x, -4
%c2 = icmp ule i8 %add, %y
%and = and i1 %c1, %c2
ret i1 %and
}
; ==============================================================================
; Tests with multiple uses
; ==============================================================================
define i1 @eq_multi_c1(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @eq_multi_c1(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[X]], 0
; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X]], -1
; CHECK-NEXT: [[OR:%.*]] = icmp uge i8 [[TMP1]], [[Y]]
; CHECK-NEXT: call void @use(i1 [[C1]])
; CHECK-NEXT: ret i1 [[OR]]
;
%c1 = icmp eq i8 %x, 0
%c2 = icmp ugt i8 %x, %y
%or = or i1 %c1, %c2
call void @use(i1 %c1)
ret i1 %or
}
define i1 @ne_multi_c2(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @ne_multi_c2(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[C2:%.*]] = icmp ule i8 [[X]], [[Y]]
; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X]], -1
; CHECK-NEXT: [[AND:%.*]] = icmp ult i8 [[TMP1]], [[Y]]
; CHECK-NEXT: call void @use(i1 [[C2]])
; CHECK-NEXT: ret i1 [[AND]]
;
%c1 = icmp ne i8 %x, 0
%c2 = icmp ule i8 %x, %y
%and = and i1 %c1, %c2
call void @use(i1 %c2)
ret i1 %and
}
; ==============================================================================
; Tests with vector types
; ==============================================================================
define <2 x i1> @eq_vector(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: define <2 x i1> @eq_vector(
; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i8> [[X]], <i8 -1, i8 -1>
; CHECK-NEXT: [[OR:%.*]] = icmp uge <2 x i8> [[TMP1]], [[Y]]
; CHECK-NEXT: ret <2 x i1> [[OR]]
;
%c1 = icmp eq <2 x i8> %x, <i8 0, i8 0>
%c2 = icmp ugt <2 x i8> %x, %y
%or = or <2 x i1> %c1, %c2
ret <2 x i1> %or
}
define <2 x i1> @ne_vector_equal_5(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: define <2 x i1> @ne_vector_equal_5(
; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i8> [[X]], <i8 -6, i8 -6>
; CHECK-NEXT: [[AND:%.*]] = icmp ult <2 x i8> [[TMP1]], [[Y]]
; CHECK-NEXT: ret <2 x i1> [[AND]]
;
%sub = add <2 x i8> %x, <i8 -5, i8 -5>
%c1 = icmp ne <2 x i8> %x, <i8 5, i8 5>
%c2 = icmp ule <2 x i8> %sub, %y
%and = and <2 x i1> %c1, %c2
ret <2 x i1> %and
}
define <2 x i1> @eq_vector_equal_minus_1(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: define <2 x i1> @eq_vector_equal_minus_1(
; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
; CHECK-NEXT: [[OR:%.*]] = icmp uge <2 x i8> [[X]], [[Y]]
; CHECK-NEXT: ret <2 x i1> [[OR]]
;
%add = add <2 x i8> %x, <i8 1, i8 1>
%c1 = icmp eq <2 x i8> %x, <i8 -1, i8 -1>
%c2 = icmp ugt <2 x i8> %add, %y
%or = or <2 x i1> %c1, %c2
ret <2 x i1> %or
}
define <2 x i1> @ne_vector_equal_minus_7(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: define <2 x i1> @ne_vector_equal_minus_7(
; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i8> [[X]], <i8 6, i8 6>
; CHECK-NEXT: [[AND:%.*]] = icmp ult <2 x i8> [[TMP1]], [[Y]]
; CHECK-NEXT: ret <2 x i1> [[AND]]
;
%add = add <2 x i8> %x, <i8 7, i8 7>
%c1 = icmp ne <2 x i8> %x, <i8 -7, i8 -7>
%c2 = icmp ule <2 x i8> %add, %y
%and = and <2 x i1> %c1, %c2
ret <2 x i1> %and
}
define <2 x i1> @eq_vector_unequal1(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: define <2 x i1> @eq_vector_unequal1(
; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
; CHECK-NEXT: [[SUB:%.*]] = add <2 x i8> [[X]], <i8 -5, i8 -5>
; CHECK-NEXT: [[C1:%.*]] = icmp eq <2 x i8> [[X]], <i8 2, i8 2>
; CHECK-NEXT: [[C2:%.*]] = icmp ugt <2 x i8> [[SUB]], [[Y]]
; CHECK-NEXT: [[OR:%.*]] = or <2 x i1> [[C1]], [[C2]]
; CHECK-NEXT: ret <2 x i1> [[OR]]
;
%sub = add <2 x i8> %x, <i8 -5, i8 -5>
%c1 = icmp eq <2 x i8> %x, <i8 2, i8 2>
%c2 = icmp ugt <2 x i8> %sub, %y
%or = or <2 x i1> %c1, %c2
ret <2 x i1> %or
}
define <2 x i1> @ne_vector_unequal2(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: define <2 x i1> @ne_vector_unequal2(
; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
; CHECK-NEXT: [[ADD:%.*]] = add <2 x i8> [[X]], <i8 7, i8 7>
; CHECK-NEXT: [[C1:%.*]] = icmp ne <2 x i8> [[X]], <i8 -3, i8 -3>
; CHECK-NEXT: [[C2:%.*]] = icmp ule <2 x i8> [[ADD]], [[Y]]
; CHECK-NEXT: [[AND:%.*]] = and <2 x i1> [[C1]], [[C2]]
; CHECK-NEXT: ret <2 x i1> [[AND]]
;
%add = add <2 x i8> %x, <i8 7, i8 7>
%c1 = icmp ne <2 x i8> %x, <i8 -3, i8 -3>
%c2 = icmp ule <2 x i8> %add, %y
%and = and <2 x i1> %c1, %c2
ret <2 x i1> %and
}
; ==============================================================================
; Tests with poison
; ==============================================================================
define <2 x i1> @eq_vector_poison_icmp(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: define <2 x i1> @eq_vector_poison_icmp(
; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i8> [[X]], <i8 -6, i8 -6>
; CHECK-NEXT: [[OR:%.*]] = icmp uge <2 x i8> [[TMP1]], [[Y]]
; CHECK-NEXT: ret <2 x i1> [[OR]]
;
%sub = add <2 x i8> %x, <i8 -5, i8 -5>
%c1 = icmp eq <2 x i8> %x, <i8 5, i8 poison>
%c2 = icmp ugt <2 x i8> %sub, %y
%or = or <2 x i1> %c1, %c2
ret <2 x i1> %or
}
define <2 x i1> @eq_vector_poison_add(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: define <2 x i1> @eq_vector_poison_add(
; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i8> [[X]], <i8 -6, i8 -6>
; CHECK-NEXT: [[OR:%.*]] = icmp uge <2 x i8> [[TMP1]], [[Y]]
; CHECK-NEXT: ret <2 x i1> [[OR]]
;
%sub = add <2 x i8> %x, <i8 -5, i8 poison>
%c1 = icmp eq <2 x i8> %x, <i8 5, i8 5>
%c2 = icmp ugt <2 x i8> %sub, %y
%or = or <2 x i1> %c1, %c2
ret <2 x i1> %or
}
; ==============================================================================
; Tests with values commuted
; ==============================================================================
define i1 @eq_commuted(i8 %x, i8 %py) {
; CHECK-LABEL: define i1 @eq_commuted(
; CHECK-SAME: i8 [[X:%.*]], i8 [[PY:%.*]]) {
; CHECK-NEXT: [[Y:%.*]] = sdiv i8 43, [[PY]]
; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X]], -1
; CHECK-NEXT: [[OR:%.*]] = icmp uge i8 [[TMP1]], [[Y]]
; CHECK-NEXT: ret i1 [[OR]]
;
%y = sdiv i8 43, %py ; thwart complexity-based canonicalization
%c1 = icmp eq i8 %x, 0
%c2 = icmp ult i8 %y, %x
%or = or i1 %c1, %c2
ret i1 %or
}
define i1 @ne_commuted_equal_minus_1(i8 %x, i8 %py) {
; CHECK-LABEL: define i1 @ne_commuted_equal_minus_1(
; CHECK-SAME: i8 [[X:%.*]], i8 [[PY:%.*]]) {
; CHECK-NEXT: [[Y:%.*]] = sdiv i8 42, [[PY]]
; CHECK-NEXT: [[AND:%.*]] = icmp ult i8 [[X]], [[Y]]
; CHECK-NEXT: ret i1 [[AND]]
;
%y = sdiv i8 42, %py ; thwart complexity-based canonicalization
%add = add i8 %x, 1
%c1 = icmp ne i8 %x, -1
%c2 = icmp uge i8 %y, %add
%and = and i1 %c1, %c2
ret i1 %and
}
declare void @use(i1)