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 @@ -3219,6 +3219,21 @@ return TrueIfSignedL == TrueIfSignedR ? Builder.CreateIsNeg(XorLR) : Builder.CreateIsNotNeg(XorLR); } + + // (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 (LHS0 == RHS0 && *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 @@ -222,14 +222,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 @@ -239,10 +235,8 @@ 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:%.*]], 5 +; CHECK-NEXT: ret i1 [[TMP1]] ; %c = icmp sgt i64 %a, 4 %b = icmp slt i64 %a, 6 @@ -252,10 +246,8 @@ 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]] +; 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 @@ -265,10 +257,8 @@ define <2 x i1> @xor_of_icmps_to_ne_vector(<2 x i64> %a) { ; CHECK-LABEL: @xor_of_icmps_to_ne_vector( -; CHECK-NEXT: [[B:%.*]] = icmp sgt <2 x i64> [[A:%.*]], -; CHECK-NEXT: [[C:%.*]] = icmp slt <2 x i64> [[A]], -; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i1> [[B]], [[C]] -; CHECK-NEXT: ret <2 x i1> [[XOR]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <2 x i64> [[A:%.*]], +; CHECK-NEXT: ret <2 x i1> [[TMP1]] ; %b = icmp sgt <2 x i64> %a, %c = icmp slt <2 x i64> %a, @@ -292,10 +282,9 @@ define i1 @xor_of_icmps_to_ne_extra_use_one(i64 %a) { ; CHECK-LABEL: @xor_of_icmps_to_ne_extra_use_one( ; CHECK-NEXT: [[B:%.*]] = icmp sgt i64 [[A:%.*]], 4 -; CHECK-NEXT: [[C:%.*]] = icmp slt i64 [[A]], 6 ; CHECK-NEXT: call void @use(i1 [[B]]) -; 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