[InstCombine] icmp Pred (shl nsw X, C1), C0 --> icmp Pred X, C0 >> C1

Try harder to fold icmp with shl nsw as discussed here:
http://lists.llvm.org/pipermail/llvm-dev/2017-January/108749.html

This is similar to the 'shl nuw' transforms that were added with D25913.

This may eventually help solve:
https://llvm.org/bugs/show_bug.cgi?id=30773

Differential Revision: https://reviews.llvm.org/D28406

llvm-svn: 292492
This commit is contained in:
Sanjay Patel 2017-01-19 16:12:10 +00:00
parent 08df246407
commit 291c3d8ff2
2 changed files with 67 additions and 73 deletions

View File

@ -1912,14 +1912,42 @@ Instruction *InstCombiner::foldICmpShlConstant(ICmpInst &Cmp,
Value *X = Shl->getOperand(0);
Type *ShType = Shl->getType();
// If this is a signed comparison to 0 and the shift is sign preserving,
// use the shift LHS operand instead; isSignTest may change 'Pred', so only
// do that if we're sure to not continue on in this function.
if (Shl->hasNoSignedWrap() && isSignTest(Pred, *C))
return new ICmpInst(Pred, X, Constant::getNullValue(ShType));
// NSW guarantees that we are only shifting out sign bits from the high bits,
// so we can ASHR the compare constant without needing a mask and eliminate
// the shift.
if (Shl->hasNoSignedWrap()) {
if (Pred == ICmpInst::ICMP_SGT) {
// icmp Pred (shl nsw X, ShiftAmt), C --> icmp Pred X, (C >>s ShiftAmt)
APInt ShiftedC = C->ashr(*ShiftAmt);
return new ICmpInst(Pred, X, ConstantInt::get(ShType, ShiftedC));
}
if (Pred == ICmpInst::ICMP_EQ || Pred == ICmpInst::ICMP_NE) {
// This is the same code as the SGT case, but assert the pre-condition
// that is needed for this to work with equality predicates.
assert(C->ashr(*ShiftAmt).shl(*ShiftAmt) == *C &&
"Compare known true or false was not folded");
APInt ShiftedC = C->ashr(*ShiftAmt);
return new ICmpInst(Pred, X, ConstantInt::get(ShType, ShiftedC));
}
if (Pred == ICmpInst::ICMP_SLT) {
// SLE is the same as above, but SLE is canonicalized to SLT, so convert:
// (X << S) <=s C is equiv to X <=s (C >> S) for all C
// (X << S) <s (C + 1) is equiv to X <s (C >> S) + 1 if C <s SMAX
// (X << S) <s C is equiv to X <s ((C - 1) >> S) + 1 if C >s SMIN
assert(!C->isMinSignedValue() && "Unexpected icmp slt");
APInt ShiftedC = (*C - 1).ashr(*ShiftAmt) + 1;
return new ICmpInst(Pred, X, ConstantInt::get(ShType, ShiftedC));
}
// If this is a signed comparison to 0 and the shift is sign preserving,
// use the shift LHS operand instead; isSignTest may change 'Pred', so only
// do that if we're sure to not continue on in this function.
if (isSignTest(Pred, *C))
return new ICmpInst(Pred, X, Constant::getNullValue(ShType));
}
// A 'shl nuw' is just shifting out zeros, so adjust the compare constant
// and eliminate the shift.
// NUW guarantees that we are only shifting out zero bits from the high bits,
// so we can LSHR the compare constant without needing a mask and eliminate
// the shift.
if (Shl->hasNoUnsignedWrap()) {
if (Pred == ICmpInst::ICMP_UGT) {
// icmp Pred (shl nuw X, ShiftAmt), C --> icmp Pred X, (C >>u ShiftAmt)
@ -1945,23 +1973,14 @@ Instruction *InstCombiner::foldICmpShlConstant(ICmpInst &Cmp,
}
}
if (Cmp.isEquality()) {
if (Cmp.isEquality() && Shl->hasOneUse()) {
// Strength-reduce the shift into an 'and'.
Constant *Mask = ConstantInt::get(
ShType,
APInt::getLowBitsSet(TypeBits, TypeBits - ShiftAmt->getZExtValue()));
Value *And = Builder->CreateAnd(X, Mask, Shl->getName() + ".mask");
Constant *LShrC = ConstantInt::get(ShType, C->lshr(*ShiftAmt));
// If the shift is NSW and we compare to 0, then it is just shifting out
// sign bits, no need for an AND either.
if (Shl->hasNoSignedWrap() && *C == 0)
return new ICmpInst(Pred, X, LShrC);
if (Shl->hasOneUse()) {
// Otherwise, strength-reduce the shift into an 'and'.
Constant *Mask = ConstantInt::get(
ShType,
APInt::getLowBitsSet(TypeBits, TypeBits - ShiftAmt->getZExtValue()));
Value *And = Builder->CreateAnd(X, Mask, Shl->getName() + ".mask");
return new ICmpInst(Pred, And, LShrC);
}
return new ICmpInst(Pred, And, LShrC);
}
// Otherwise, if this is a comparison of the sign bit, simplify to and/test.

View File

@ -73,8 +73,7 @@ define <2 x i1> @icmp_shl_nsw_eq_vec(<2 x i32> %x) {
define i1 @icmp_sgt1(i8 %x) {
; CHECK-LABEL: @icmp_sgt1(
; CHECK-NEXT: [[SHL_MASK:%.*]] = and i8 %x, 127
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[SHL_MASK]], 64
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 %x, -64
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 1
@ -84,8 +83,7 @@ define i1 @icmp_sgt1(i8 %x) {
define i1 @icmp_sgt2(i8 %x) {
; CHECK-LABEL: @icmp_sgt2(
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i8 %x, 1
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[SHL]], -127
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 %x, -64
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 1
@ -95,8 +93,7 @@ define i1 @icmp_sgt2(i8 %x) {
define i1 @icmp_sgt3(i8 %x) {
; CHECK-LABEL: @icmp_sgt3(
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i8 %x, 1
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[SHL]], -16
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 %x, -8
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 1
@ -106,8 +103,7 @@ define i1 @icmp_sgt3(i8 %x) {
define i1 @icmp_sgt4(i8 %x) {
; CHECK-LABEL: @icmp_sgt4(
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i8 %x, 1
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[SHL]], -2
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 %x, -1
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 1
@ -120,8 +116,7 @@ define i1 @icmp_sgt4(i8 %x) {
define i1 @icmp_sgt5(i8 %x) {
; CHECK-LABEL: @icmp_sgt5(
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i8 %x, 1
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[SHL]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 %x, 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 1
@ -131,8 +126,7 @@ define i1 @icmp_sgt5(i8 %x) {
define i1 @icmp_sgt6(i8 %x) {
; CHECK-LABEL: @icmp_sgt6(
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i8 %x, 1
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[SHL]], 16
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 %x, 8
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 1
@ -142,8 +136,7 @@ define i1 @icmp_sgt6(i8 %x) {
define i1 @icmp_sgt7(i8 %x) {
; CHECK-LABEL: @icmp_sgt7(
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i8 %x, 1
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[SHL]], 124
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 %x, 62
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 1
@ -155,8 +148,7 @@ define i1 @icmp_sgt7(i8 %x) {
define i1 @icmp_sgt8(i8 %x) {
; CHECK-LABEL: @icmp_sgt8(
; CHECK-NEXT: [[SHL_MASK:%.*]] = and i8 %x, 127
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[SHL_MASK]], 63
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 %x, 63
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 1
@ -170,8 +162,7 @@ define i1 @icmp_sgt8(i8 %x) {
define i1 @icmp_sgt9(i8 %x) {
; CHECK-LABEL: @icmp_sgt9(
; CHECK-NEXT: [[SHL_MASK:%.*]] = and i8 %x, 1
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[SHL_MASK]], 0
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 %x, -1
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 7
@ -181,8 +172,7 @@ define i1 @icmp_sgt9(i8 %x) {
define i1 @icmp_sgt10(i8 %x) {
; CHECK-LABEL: @icmp_sgt10(
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i8 %x, 7
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[SHL]], -127
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 %x, -1
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 7
@ -192,8 +182,7 @@ define i1 @icmp_sgt10(i8 %x) {
define i1 @icmp_sgt11(i8 %x) {
; CHECK-LABEL: @icmp_sgt11(
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i8 %x, 7
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[SHL]], -2
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 %x, -1
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 7
@ -205,8 +194,7 @@ define i1 @icmp_sgt11(i8 %x) {
define <2 x i1> @icmp_sgt11_vec(<2 x i8> %x) {
; CHECK-LABEL: @icmp_sgt11_vec(
; CHECK-NEXT: [[SHL:%.*]] = shl nsw <2 x i8> %x, <i8 7, i8 7>
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[SHL]], <i8 -2, i8 -2>
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> %x, <i8 -1, i8 -1>
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%shl = shl nsw <2 x i8> %x, <i8 7, i8 7>
@ -226,8 +214,7 @@ define <2 x i1> @icmp_sgt11_vec(<2 x i8> %x) {
define i1 @icmp_sle1(i8 %x) {
; CHECK-LABEL: @icmp_sle1(
; CHECK-NEXT: [[SHL_MASK:%.*]] = and i8 %x, 127
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[SHL_MASK]], 64
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 %x, -64
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 1
@ -237,8 +224,7 @@ define i1 @icmp_sle1(i8 %x) {
define i1 @icmp_sle2(i8 %x) {
; CHECK-LABEL: @icmp_sle2(
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i8 %x, 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[SHL]], -126
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 %x, -63
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 1
@ -248,8 +234,7 @@ define i1 @icmp_sle2(i8 %x) {
define i1 @icmp_sle3(i8 %x) {
; CHECK-LABEL: @icmp_sle3(
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i8 %x, 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[SHL]], -15
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 %x, -7
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 1
@ -259,8 +244,7 @@ define i1 @icmp_sle3(i8 %x) {
define i1 @icmp_sle4(i8 %x) {
; CHECK-LABEL: @icmp_sle4(
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i8 %x, 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[SHL]], -1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 %x, 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 1
@ -273,8 +257,7 @@ define i1 @icmp_sle4(i8 %x) {
define i1 @icmp_sle5(i8 %x) {
; CHECK-LABEL: @icmp_sle5(
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i8 %x, 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[SHL]], 2
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 %x, 1
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 1
@ -284,8 +267,7 @@ define i1 @icmp_sle5(i8 %x) {
define i1 @icmp_sle6(i8 %x) {
; CHECK-LABEL: @icmp_sle6(
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i8 %x, 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[SHL]], 17
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 %x, 9
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 1
@ -295,8 +277,7 @@ define i1 @icmp_sle6(i8 %x) {
define i1 @icmp_sle7(i8 %x) {
; CHECK-LABEL: @icmp_sle7(
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i8 %x, 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[SHL]], 125
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 %x, 63
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 1
@ -308,8 +289,7 @@ define i1 @icmp_sle7(i8 %x) {
define i1 @icmp_sle8(i8 %x) {
; CHECK-LABEL: @icmp_sle8(
; CHECK-NEXT: [[SHL_MASK:%.*]] = and i8 %x, 127
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[SHL_MASK]], 63
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 %x, 63
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 1
@ -323,8 +303,7 @@ define i1 @icmp_sle8(i8 %x) {
define i1 @icmp_sle9(i8 %x) {
; CHECK-LABEL: @icmp_sle9(
; CHECK-NEXT: [[SHL_MASK:%.*]] = and i8 %x, 1
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[SHL_MASK]], 0
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 %x, -1
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 7
@ -334,8 +313,7 @@ define i1 @icmp_sle9(i8 %x) {
define i1 @icmp_sle10(i8 %x) {
; CHECK-LABEL: @icmp_sle10(
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i8 %x, 7
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[SHL]], -126
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 %x, 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 7
@ -345,8 +323,7 @@ define i1 @icmp_sle10(i8 %x) {
define i1 @icmp_sle11(i8 %x) {
; CHECK-LABEL: @icmp_sle11(
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i8 %x, 7
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[SHL]], -1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 %x, 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 7
@ -359,8 +336,7 @@ define i1 @icmp_sle11(i8 %x) {
define i1 @icmp_eq1(i8 %x) {
; CHECK-LABEL: @icmp_eq1(
; CHECK-NEXT: [[SHL_MASK:%.*]] = and i8 %x, 127
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[SHL_MASK]], 6
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 %x, 6
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 1
@ -370,8 +346,7 @@ define i1 @icmp_eq1(i8 %x) {
define i1 @icmp_ne1(i8 %x) {
; CHECK-LABEL: @icmp_ne1(
; CHECK-NEXT: [[SHL_MASK:%.*]] = and i8 %x, 3
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[SHL_MASK]], 2
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 %x, -2
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 6