diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index e080e7f95168e..63be48fe352f4 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -2592,12 +2592,13 @@ Instruction *InstCombinerImpl::foldICmpSubConstant(ICmpInst &Cmp, // (icmp P (sub nuw|nsw C2, Y), C) -> (icmp swap(P) Y, C2-C) const APInt *C2; APInt SubResult; + ICmpInst::Predicate SwappedPred = Cmp.getSwappedPredicate(); + bool HasNSW = Sub->hasNoSignedWrap(); + bool HasNUW = Sub->hasNoUnsignedWrap(); if (match(X, m_APInt(C2)) && - ((Cmp.isUnsigned() && Sub->hasNoUnsignedWrap()) || - (Cmp.isSigned() && Sub->hasNoSignedWrap())) && + ((Cmp.isUnsigned() && HasNUW) || (Cmp.isSigned() && HasNSW)) && !subWithOverflow(SubResult, *C2, C, Cmp.isSigned())) - return new ICmpInst(Cmp.getSwappedPredicate(), Y, - ConstantInt::get(Ty, SubResult)); + return new ICmpInst(SwappedPred, Y, ConstantInt::get(Ty, SubResult)); // The following transforms are only worth it if the only user of the subtract // is the icmp. @@ -2636,7 +2637,12 @@ Instruction *InstCombinerImpl::foldICmpSubConstant(ICmpInst &Cmp, if (Pred == ICmpInst::ICMP_UGT && (C + 1).isPowerOf2() && (*C2 & C) == C) return new ICmpInst(ICmpInst::ICMP_NE, Builder.CreateOr(Y, C), X); - return nullptr; + // We have handled special cases that reduce. + // Canonicalize any remaining sub to add as: + // (C2 - Y) > C --> (Y + ~C2) < ~C + Value *Add = Builder.CreateAdd(Y, ConstantInt::get(Ty, ~(*C2)), "notsub", + HasNUW, HasNSW); + return new ICmpInst(SwappedPred, Add, ConstantInt::get(Ty, ~C)); } /// Fold icmp (add X, Y), C. diff --git a/llvm/test/Transforms/InstCombine/2007-12-18-AddSelCmpSub.ll b/llvm/test/Transforms/InstCombine/2007-12-18-AddSelCmpSub.ll index 62fb4132d5de6..38721f3079a66 100644 --- a/llvm/test/Transforms/InstCombine/2007-12-18-AddSelCmpSub.ll +++ b/llvm/test/Transforms/InstCombine/2007-12-18-AddSelCmpSub.ll @@ -3,10 +3,10 @@ define i32 @foo(i32 %a) { ; CHECK-LABEL: @foo( -; CHECK-NEXT: [[T15:%.*]] = sub i32 99, [[A:%.*]] -; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[T15]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[A:%.*]], -100 +; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], -1 ; CHECK-NEXT: [[A_OP:%.*]] = add i32 [[A]], 1 -; CHECK-NEXT: [[T13:%.*]] = select i1 [[TMP1]], i32 100, i32 [[A_OP]] +; CHECK-NEXT: [[T13:%.*]] = select i1 [[TMP2]], i32 100, i32 [[A_OP]] ; CHECK-NEXT: ret i32 [[T13]] ; %t15 = sub i32 99, %a @@ -19,9 +19,9 @@ define i32 @foo(i32 %a) { define i32 @bar(i32 %a) { ; CHECK-LABEL: @bar( -; CHECK-NEXT: [[T15:%.*]] = sub i32 99, [[A:%.*]] -; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[T15]], 0 -; CHECK-NEXT: [[T12:%.*]] = select i1 [[TMP1]], i32 99, i32 [[A]] +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[A:%.*]], -100 +; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], -1 +; CHECK-NEXT: [[T12:%.*]] = select i1 [[TMP2]], i32 99, i32 [[A]] ; CHECK-NEXT: ret i32 [[T12]] ; %t15 = sub i32 99, %a diff --git a/llvm/test/Transforms/InstCombine/icmp-sub.ll b/llvm/test/Transforms/InstCombine/icmp-sub.ll index 0b62df6042585..03488a2f469a3 100644 --- a/llvm/test/Transforms/InstCombine/icmp-sub.ll +++ b/llvm/test/Transforms/InstCombine/icmp-sub.ll @@ -46,8 +46,8 @@ define i1 @test_nuw_nsw_and_signed_pred(i64 %x) { define i1 @test_negative_nuw_and_signed_pred(i64 %x) { ; CHECK-LABEL: @test_negative_nuw_and_signed_pred( -; CHECK-NEXT: [[Y:%.*]] = sub nuw i64 10, [[X:%.*]] -; CHECK-NEXT: [[Z:%.*]] = icmp slt i64 [[Y]], 3 +; CHECK-NEXT: [[NOTSUB:%.*]] = add nuw i64 [[X:%.*]], -11 +; CHECK-NEXT: [[Z:%.*]] = icmp sgt i64 [[NOTSUB]], -4 ; CHECK-NEXT: ret i1 [[Z]] ; %y = sub nuw i64 10, %x @@ -57,8 +57,8 @@ define i1 @test_negative_nuw_and_signed_pred(i64 %x) { define i1 @test_negative_nsw_and_unsigned_pred(i64 %x) { ; CHECK-LABEL: @test_negative_nsw_and_unsigned_pred( -; CHECK-NEXT: [[Y:%.*]] = sub nsw i64 10, [[X:%.*]] -; CHECK-NEXT: [[Z:%.*]] = icmp ult i64 [[Y]], 3 +; CHECK-NEXT: [[NOTSUB:%.*]] = add nsw i64 [[X:%.*]], -11 +; CHECK-NEXT: [[Z:%.*]] = icmp ugt i64 [[NOTSUB]], -4 ; CHECK-NEXT: ret i1 [[Z]] ; %y = sub nsw i64 10, %x @@ -68,9 +68,7 @@ define i1 @test_negative_nsw_and_unsigned_pred(i64 %x) { define i1 @test_negative_combined_sub_unsigned_overflow(i64 %x) { ; CHECK-LABEL: @test_negative_combined_sub_unsigned_overflow( -; CHECK-NEXT: [[Y:%.*]] = sub nuw i64 10, [[X:%.*]] -; CHECK-NEXT: [[Z:%.*]] = icmp ult i64 [[Y]], 11 -; CHECK-NEXT: ret i1 [[Z]] +; CHECK-NEXT: ret i1 true ; %y = sub nuw i64 10, %x %z = icmp ult i64 %y, 11 @@ -79,9 +77,7 @@ define i1 @test_negative_combined_sub_unsigned_overflow(i64 %x) { define i1 @test_negative_combined_sub_signed_overflow(i8 %x) { ; CHECK-LABEL: @test_negative_combined_sub_signed_overflow( -; CHECK-NEXT: [[Y:%.*]] = sub nsw i8 127, [[X:%.*]] -; CHECK-NEXT: [[Z:%.*]] = icmp slt i8 [[Y]], -1 -; CHECK-NEXT: ret i1 [[Z]] +; CHECK-NEXT: ret i1 false ; %y = sub nsw i8 127, %x %z = icmp slt i8 %y, -1 @@ -191,8 +187,8 @@ define <2 x i1> @icmp_eq_sub_non_splat2(<2 x i32> %a) { define i1 @neg_sgt_42(i32 %x) { ; CHECK-LABEL: @neg_sgt_42( -; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp sgt i32 [[NEGX]], 42 +; CHECK-NEXT: [[NOTSUB:%.*]] = add i32 [[X:%.*]], -1 +; CHECK-NEXT: [[R:%.*]] = icmp slt i32 [[NOTSUB]], -43 ; CHECK-NEXT: ret i1 [[R]] ; %negx = sub i32 0, %x @@ -306,8 +302,8 @@ define i1 @subC_nsw_ne(i32 %x) { define i1 @neg_slt_42(i128 %x) { ; CHECK-LABEL: @neg_slt_42( -; CHECK-NEXT: [[NEGX:%.*]] = sub i128 0, [[X:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp slt i128 [[NEGX]], 42 +; CHECK-NEXT: [[NOTSUB:%.*]] = add i128 [[X:%.*]], -1 +; CHECK-NEXT: [[R:%.*]] = icmp sgt i128 [[NOTSUB]], -43 ; CHECK-NEXT: ret i1 [[R]] ; %negx = sub i128 0, %x @@ -317,8 +313,8 @@ define i1 @neg_slt_42(i128 %x) { define <2 x i1> @neg_ugt_42_splat(<2 x i7> %x) { ; CHECK-LABEL: @neg_ugt_42_splat( -; CHECK-NEXT: [[NEGX:%.*]] = sub <2 x i7> zeroinitializer, [[X:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp ugt <2 x i7> [[NEGX]], +; CHECK-NEXT: [[NOTSUB:%.*]] = add <2 x i7> [[X:%.*]], +; CHECK-NEXT: [[R:%.*]] = icmp ult <2 x i7> [[NOTSUB]], ; CHECK-NEXT: ret <2 x i1> [[R]] ; %negx = sub <2 x i7> zeroinitializer, %x @@ -343,8 +339,8 @@ define i1 @neg_sgt_42_use(i32 %x) { define i1 @neg_slt_n1(i8 %x) { ; CHECK-LABEL: @neg_slt_n1( -; CHECK-NEXT: [[NEGX:%.*]] = sub i8 0, [[X:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[NEGX]], -1 +; CHECK-NEXT: [[NOTSUB:%.*]] = add i8 [[X:%.*]], -1 +; CHECK-NEXT: [[R:%.*]] = icmp sgt i8 [[NOTSUB]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %negx = sub i8 0, %x @@ -354,8 +350,8 @@ define i1 @neg_slt_n1(i8 %x) { define i1 @neg_slt_0(i8 %x) { ; CHECK-LABEL: @neg_slt_0( -; CHECK-NEXT: [[NEGX:%.*]] = sub i8 0, [[X:%.*]] -; CHECK-NEXT: [[ISNEGNEG:%.*]] = icmp slt i8 [[NEGX]], 0 +; CHECK-NEXT: [[NOTSUB:%.*]] = add i8 [[X:%.*]], -1 +; CHECK-NEXT: [[ISNEGNEG:%.*]] = icmp sgt i8 [[NOTSUB]], -1 ; CHECK-NEXT: ret i1 [[ISNEGNEG]] ; %negx = sub i8 0, %x @@ -365,8 +361,7 @@ define i1 @neg_slt_0(i8 %x) { define i1 @neg_slt_1(i8 %x) { ; CHECK-LABEL: @neg_slt_1( -; CHECK-NEXT: [[NEGX:%.*]] = sub i8 0, [[X:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[NEGX]], 1 +; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[X:%.*]], -127 ; CHECK-NEXT: ret i1 [[R]] ; %negx = sub i8 0, %x @@ -376,8 +371,8 @@ define i1 @neg_slt_1(i8 %x) { define i1 @neg_sgt_n1(i8 %x) { ; CHECK-LABEL: @neg_sgt_n1( -; CHECK-NEXT: [[NEGX:%.*]] = sub i8 0, [[X:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp sgt i8 [[NEGX]], -1 +; CHECK-NEXT: [[NOTSUB:%.*]] = add i8 [[X:%.*]], -1 +; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[NOTSUB]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %negx = sub i8 0, %x @@ -387,8 +382,7 @@ define i1 @neg_sgt_n1(i8 %x) { define i1 @neg_sgt_0(i8 %x) { ; CHECK-LABEL: @neg_sgt_0( -; CHECK-NEXT: [[NEGX:%.*]] = sub i8 0, [[X:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp sgt i8 [[NEGX]], 0 +; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[X:%.*]], -128 ; CHECK-NEXT: ret i1 [[R]] ; %negx = sub i8 0, %x @@ -398,8 +392,8 @@ define i1 @neg_sgt_0(i8 %x) { define i1 @neg_sgt_1(i8 %x) { ; CHECK-LABEL: @neg_sgt_1( -; CHECK-NEXT: [[NEGX:%.*]] = sub i8 0, [[X:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp sgt i8 [[NEGX]], 1 +; CHECK-NEXT: [[NOTSUB:%.*]] = add i8 [[X:%.*]], -1 +; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[NOTSUB]], -2 ; CHECK-NEXT: ret i1 [[R]] ; %negx = sub i8 0, %x diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll index 90f4f45935353..5b4bff6f0c291 100644 --- a/llvm/test/Transforms/InstCombine/or.ll +++ b/llvm/test/Transforms/InstCombine/or.ll @@ -1447,11 +1447,10 @@ define i8 @lshr_bitwidth_mask(i8 %x, i8 %y) { define i1 @cmp_overlap(i32 %x) { ; CHECK-LABEL: @cmp_overlap( -; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[X:%.*]], 0 -; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X]] -; CHECK-NEXT: [[ISNOTNEG:%.*]] = icmp sgt i32 [[NEGX]], -1 -; CHECK-NEXT: [[R:%.*]] = or i1 [[ISNEG]], [[ISNOTNEG]] -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: [[NOTSUB:%.*]] = add i32 [[X:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[NOTSUB]], [[X]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0 +; CHECK-NEXT: ret i1 [[TMP2]] ; %isneg = icmp slt i32 %x, 0 %negx = sub i32 0, %x