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'
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
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
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
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:%.*]], <i64 4, i64 4>
-; CHECK-NEXT: [[C:%.*]] = icmp slt <2 x i64> [[A]], <i64 6, i64 6>
-; 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:%.*]], <i64 5, i64 5>
+; CHECK-NEXT: ret <2 x i1> [[TMP1]]
;
%b = icmp sgt <2 x i64> %a, <i64 4, i64 4>
%c = icmp slt <2 x i64> %a, <i64 6, i64 6>
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