Value *X = Add->getOperand(0);
Type *Ty = Add->getType();
CmpInst::Predicate Pred = Cmp.getPredicate();
+
+ // If the add does not wrap, we can always adjust the compare by subtracting
+ // the constants. Equality comparisons are handled elsewhere. SGE/SLE are
+ // canonicalized to SGT/SLT.
+ if (Add->hasNoSignedWrap() &&
+ (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLT)) {
+ bool Overflow;
+ APInt NewC = C->ssub_ov(*C2, Overflow);
+ // If there is overflow, the result must be true or false.
+ // TODO: Can we assert there is no overflow because InstSimplify always
+ // handles those cases?
+ if (!Overflow)
+ // icmp Pred (add nsw X, C2), C --> icmp Pred X, (C - C2)
+ return new ICmpInst(Pred, X, ConstantInt::get(Ty, NewC));
+ }
+
auto CR = ConstantRange::makeExactICmpRegion(Pred, *C).subtract(*C2);
const APInt &Upper = CR.getUpper();
const APInt &Lower = CR.getLower();
D = BO1->getOperand(1);
}
- // icmp (X+cst) < 0 --> X < -cst
- if (NoOp0WrapProblem && ICmpInst::isSigned(Pred) && match(Op1, m_Zero()))
- if (ConstantInt *RHSC = dyn_cast_or_null<ConstantInt>(B))
- if (!RHSC->isMinValue(/*isSigned=*/true))
- return new ICmpInst(Pred, A, ConstantExpr::getNeg(RHSC));
-
// icmp (X+Y), X -> icmp Y, 0 for equalities or if there is no overflow.
if ((A == Op1 || B == Op1) && NoOp0WrapProblem)
return new ICmpInst(Pred, A == Op1 ? B : A,
define i1 @nsw_slt1(i8 %a) {
; CHECK-LABEL: @nsw_slt1(
-; CHECK-NEXT: [[B:%.*]] = add nsw i8 %a, 100
-; CHECK-NEXT: [[C:%.*]] = icmp slt i8 [[B]], -27
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 %a, -128
; CHECK-NEXT: ret i1 [[C]]
;
%b = add nsw i8 %a, 100
define i1 @nsw_slt2(i8 %a) {
; CHECK-LABEL: @nsw_slt2(
-; CHECK-NEXT: [[B:%.*]] = add nsw i8 %a, -100
-; CHECK-NEXT: [[C:%.*]] = icmp slt i8 [[B]], 27
+; CHECK-NEXT: [[C:%.*]] = icmp ne i8 %a, 127
; CHECK-NEXT: ret i1 [[C]]
;
%b = add nsw i8 %a, -100
define i1 @nsw_slt3(i8 %a) {
; CHECK-LABEL: @nsw_slt3(
-; CHECK-NEXT: [[B:%.*]] = add nsw i8 %a, 100
-; CHECK-NEXT: [[C:%.*]] = icmp slt i8 [[B]], -26
+; CHECK-NEXT: [[C:%.*]] = icmp slt i8 %a, -126
; CHECK-NEXT: ret i1 [[C]]
;
%b = add nsw i8 %a, 100
define i1 @nsw_slt4(i8 %a) {
; CHECK-LABEL: @nsw_slt4(
-; CHECK-NEXT: [[B:%.*]] = add nsw i8 %a, -100
-; CHECK-NEXT: [[C:%.*]] = icmp slt i8 [[B]], 26
+; CHECK-NEXT: [[C:%.*]] = icmp slt i8 %a, 126
; CHECK-NEXT: ret i1 [[C]]
;
%b = add nsw i8 %a, -100
define i1 @nsw_sgt1(i8 %a) {
; CHECK-LABEL: @nsw_sgt1(
-; CHECK-NEXT: [[B:%.*]] = add nsw i8 %a, -100
-; CHECK-NEXT: [[C:%.*]] = icmp sgt i8 [[B]], 26
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 %a, 127
; CHECK-NEXT: ret i1 [[C]]
;
%b = add nsw i8 %a, -100
; icmp Pred (add nsw X, C2), C --> icmp Pred X, (C - C2), when C - C2 does not overflow.
; Try a vector type to make sure that works too.
+; FIXME: This should be 'eq 127' as above.
define <2 x i1> @nsw_sgt2_splat_vec(<2 x i8> %a) {
; CHECK-LABEL: @nsw_sgt2_splat_vec(
-; CHECK-NEXT: [[B:%.*]] = add nsw <2 x i8> %a, <i8 100, i8 100>
-; CHECK-NEXT: [[C:%.*]] = icmp sgt <2 x i8> [[B]], <i8 -26, i8 -26>
+; CHECK-NEXT: [[C:%.*]] = icmp sgt <2 x i8> %a, <i8 -126, i8 -126>
; CHECK-NEXT: ret <2 x i1> [[C]]
;
%b = add nsw <2 x i8> %a, <i8 100, i8 100>
ret i1 %cmp
}
-; FIXME: The same fold should work with vectors.
+; The same fold should work with vectors.
define <2 x i1> @slt_zero_add_nsw_splat_vec(<2 x i8> %a) {
; CHECK-LABEL: @slt_zero_add_nsw_splat_vec(
-; CHECK-NEXT: [[ADD:%.*]] = add nsw <2 x i8> %a, <i8 1, i8 1>
-; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[ADD]], zeroinitializer
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> %a, <i8 -1, i8 -1>
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%add = add nsw <2 x i8> %a, <i8 1, i8 1>