diff options
| author | Sanjay Patel <spatel@rotateright.com> | 2017-01-19 16:12:10 +0000 |
|---|---|---|
| committer | Sanjay Patel <spatel@rotateright.com> | 2017-01-19 16:12:10 +0000 |
| commit | 291c3d8ff21652a7bd654cfc170e0891e46a84da (patch) | |
| tree | d89a555a5af16e7b7431e921767fc52ddb55dc27 | |
| parent | 08df2464073f32c997c3ab39b6a3944a75923884 (diff) | |
| download | bcm5719-llvm-291c3d8ff21652a7bd654cfc170e0891e46a84da.tar.gz bcm5719-llvm-291c3d8ff21652a7bd654cfc170e0891e46a84da.zip | |
[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
| -rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 67 | ||||
| -rw-r--r-- | llvm/test/Transforms/InstCombine/icmp-shl-nsw.ll | 75 |
2 files changed, 68 insertions, 74 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index c6e15c73420..3ebf719fceb 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -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)); - - // A 'shl nuw' is just shifting out zeros, so adjust the compare constant - // and eliminate the shift. + // 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)); + } + + // 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. diff --git a/llvm/test/Transforms/InstCombine/icmp-shl-nsw.ll b/llvm/test/Transforms/InstCombine/icmp-shl-nsw.ll index c12a39d3bb3..ba05302897e 100644 --- a/llvm/test/Transforms/InstCombine/icmp-shl-nsw.ll +++ b/llvm/test/Transforms/InstCombine/icmp-shl-nsw.ll @@ -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 |

