// (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.
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.
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
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
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
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
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
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
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
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
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]], <i7 42, i7 42>
+; CHECK-NEXT: [[NOTSUB:%.*]] = add <2 x i7> [[X:%.*]], <i7 -1, i7 -1>
+; CHECK-NEXT: [[R:%.*]] = icmp ult <2 x i7> [[NOTSUB]], <i7 -43, i7 -43>
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%negx = sub <2 x i7> zeroinitializer, %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
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
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
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
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
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