diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -3221,6 +3221,19 @@ PredR == CmpInst::ICMP_SGT && match(RHS1, m_AllOnes()))) return Builder.CreateIsNotNeg(Builder.CreateXor(LHS0, RHS0)); + // (X > C) ^ (X < C + 2) --> X != C + 1 + // (X < C + 2) ^ (X > C) --> X != C + 1 + // Considering the correctness of this pattern, we should avoid that C is + // non-negative and C + 2 is negative, although it will be matched by other + // patterns. + const APInt *C1, *C2; + if ((PredL == CmpInst::ICMP_SGT && match(LHS1, m_APInt(C1)) && + PredR == CmpInst::ICMP_SLT && match(RHS1, m_APInt(C2))) || + (PredL == CmpInst::ICMP_SLT && match(LHS1, m_APInt(C2)) && + PredR == CmpInst::ICMP_SGT && match(RHS1, m_APInt(C1)))) + if (*C1 + 2 == *C2 && (C1->isNegative() || C2->isNonNegative())) + return Builder.CreateICmpNE(LHS0, + ConstantInt::get(LHS0->getType(), *C1 + 1)); } // Instead of trying to imitate the folds for and/or, decompose this 'xor' diff --git a/llvm/test/Transforms/InstCombine/set.ll b/llvm/test/Transforms/InstCombine/set.ll --- a/llvm/test/Transforms/InstCombine/set.ll +++ b/llvm/test/Transforms/InstCombine/set.ll @@ -220,14 +220,10 @@ ret i1 %xor } -; FIXME: This is (a != 5). - define i1 @xor_of_icmps_to_ne(i64 %a) { ; CHECK-LABEL: @xor_of_icmps_to_ne( -; CHECK-NEXT: [[B:%.*]] = icmp sgt i64 [[A:%.*]], 4 -; CHECK-NEXT: [[C:%.*]] = icmp slt i64 [[A]], 6 -; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[B]], [[C]] -; CHECK-NEXT: ret i1 [[XOR]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A:%.*]], 5 +; CHECK-NEXT: ret i1 [[TMP1]] ; %b = icmp sgt i64 %a, 4 %c = icmp slt i64 %a, 6 @@ -237,23 +233,19 @@ define i1 @xor_of_icmps_to_ne_commute(i64 %a) { ; CHECK-LABEL: @xor_of_icmps_to_ne_commute( -; CHECK-NEXT: [[C:%.*]] = icmp sgt i64 [[A:%.*]], 4 -; CHECK-NEXT: [[B:%.*]] = icmp slt i64 [[A]], 6 -; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[B]], [[C]] -; CHECK-NEXT: ret i1 [[XOR]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A:%.*]], 1 +; CHECK-NEXT: ret i1 [[TMP1]] ; - %c = icmp sgt i64 %a, 4 - %b = icmp slt i64 %a, 6 + %c = icmp sgt i64 %a, 0 + %b = icmp slt i64 %a, 2 %xor = xor i1 %b, %c ret i1 %xor } -define i1 @xor_of_icmps_neg_to_ne(i64 %a) { -; CHECK-LABEL: @xor_of_icmps_neg_to_ne( -; CHECK-NEXT: [[B:%.*]] = icmp sgt i64 [[A:%.*]], -6 -; CHECK-NEXT: [[C:%.*]] = icmp slt i64 [[A]], -4 -; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[B]], [[C]] -; CHECK-NEXT: ret i1 [[XOR]] +define i1 @xor_of_icmps_negs_to_ne(i64 %a) { +; CHECK-LABEL: @xor_of_icmps_negs_to_ne( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A:%.*]], -5 +; CHECK-NEXT: ret i1 [[TMP1]] ; %b = icmp sgt i64 %a, -6 %c = icmp slt i64 %a, -4 @@ -261,6 +253,29 @@ ret i1 %xor } + +define i1 @xor_of_icmps_neg_non-neg_to_eq(i8 %x) { +; CHECK-LABEL: @xor_of_icmps_neg_non-neg_to_eq( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i8 [[X:%.*]], -1 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %b = icmp sgt i8 %x, -2 + %c = icmp slt i8 %x, 0 + %xor = xor i1 %b, %c + ret i1 %xor +} + +define i1 @xor_of_icmps_neg_non-neg_to_eq_more(i8 %x) { +; CHECK-LABEL: @xor_of_icmps_neg_non-neg_to_eq_more( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i8 [[X:%.*]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %b = icmp sgt i8 %x, -1 + %c = icmp slt i8 %x, 1 + %xor = xor i1 %b, %c + ret i1 %xor +} + define i1 @xor_of_icmps_to_eq(i8 %a) { ; CHECK-LABEL: @xor_of_icmps_to_eq( ; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[A:%.*]], 127 @@ -272,6 +287,17 @@ ret i1 %xor } +define i1 @xor_of_icmps_to_eq_1(i8 %x) { +; CHECK-LABEL: @xor_of_icmps_to_eq_1( +; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[X:%.*]], -128 +; CHECK-NEXT: ret i1 [[C]] +; + %b = icmp sgt i8 %x, 127 + %c = icmp slt i8 %x, 129 + %xor = xor i1 %b, %c + ret i1 %xor +} + ; https://bugs.llvm.org/show_bug.cgi?id=2844 define i32 @PR2844(i32 %x) {