diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index f2be0bef999e..6bd479def210 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -2640,11 +2640,16 @@ Instruction *InstCombinerImpl::foldICmpAddConstant(ICmpInst &Cmp, // Fold an unsigned compare with offset to signed compare: // (X + C2) >u C --> X getScalarSizeInBits())) return new ICmpInst(ICmpInst::ICMP_SLT, X, ConstantInt::get(Ty, -(*C2))); + // (X + C2) X >s ~C2 (if C == C2 + SMIN) + if (Pred == CmpInst::ICMP_ULT && + C == *C2 + APInt::getSignedMinValue(Ty->getScalarSizeInBits())) + return new ICmpInst(ICmpInst::ICMP_SGT, X, ConstantInt::get(Ty, ~(*C2))); + // If the add does not wrap, we can always adjust the compare by subtracting // the constants. Equality comparisons are handled elsewhere. SGE/SLE/UGE/ULE // are canonicalized to SGT/SLT/UGT/ULT. diff --git a/llvm/test/Transforms/InstCombine/icmp-add.ll b/llvm/test/Transforms/InstCombine/icmp-add.ll index 1fbc6d169f10..8ad14004076f 100644 --- a/llvm/test/Transforms/InstCombine/icmp-add.ll +++ b/llvm/test/Transforms/InstCombine/icmp-add.ll @@ -796,8 +796,7 @@ define i1 @ugt_wrong_offset(i8 %a) { define i1 @ult_offset(i8 %a) { ; CHECK-LABEL: @ult_offset( -; CHECK-NEXT: [[T:%.*]] = add i8 [[A:%.*]], -6 -; CHECK-NEXT: [[OV:%.*]] = icmp ult i8 [[T]], 122 +; CHECK-NEXT: [[OV:%.*]] = icmp sgt i8 [[A:%.*]], 5 ; CHECK-NEXT: ret i1 [[OV]] ; %t = add i8 %a, 250 @@ -809,7 +808,7 @@ define i1 @ult_offset_use(i32 %a) { ; CHECK-LABEL: @ult_offset_use( ; CHECK-NEXT: [[T:%.*]] = add i32 [[A:%.*]], 42 ; CHECK-NEXT: call void @use(i32 [[T]]) -; CHECK-NEXT: [[OV:%.*]] = icmp ult i32 [[T]], -2147483606 +; CHECK-NEXT: [[OV:%.*]] = icmp sgt i32 [[A]], -43 ; CHECK-NEXT: ret i1 [[OV]] ; %t = add i32 %a, 42 @@ -820,8 +819,7 @@ define i1 @ult_offset_use(i32 %a) { define <2 x i1> @ult_offset_splat(<2 x i5> %a) { ; CHECK-LABEL: @ult_offset_splat( -; CHECK-NEXT: [[T:%.*]] = add <2 x i5> [[A:%.*]], -; CHECK-NEXT: [[OV:%.*]] = icmp ult <2 x i5> [[T]], +; CHECK-NEXT: [[OV:%.*]] = icmp sgt <2 x i5> [[A:%.*]], ; CHECK-NEXT: ret <2 x i1> [[OV]] ; %t = add <2 x i5> %a, @@ -829,6 +827,8 @@ define <2 x i1> @ult_offset_splat(<2 x i5> %a) { ret <2 x i1> %ov } +; negative test - constants must differ by SMIN + define i1 @ult_wrong_offset(i8 %a) { ; CHECK-LABEL: @ult_wrong_offset( ; CHECK-NEXT: [[T:%.*]] = add i8 [[A:%.*]], -6