[llvm] r292492 - [InstCombine] icmp Pred (shl nsw X, C1), C0 --> icmp Pred X, C0 >> C1
Sanjay Patel via llvm-commits
llvm-commits at lists.llvm.org
Thu Jan 19 08:12:10 PST 2017
Author: spatel
Date: Thu Jan 19 10:12:10 2017
New Revision: 292492
URL: http://llvm.org/viewvc/llvm-project?rev=292492&view=rev
Log:
[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
Modified:
llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp
llvm/trunk/test/Transforms/InstCombine/icmp-shl-nsw.ll
Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp?rev=292492&r1=292491&r2=292492&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp Thu Jan 19 10:12:10 2017
@@ -1912,14 +1912,42 @@ Instruction *InstCombiner::foldICmpShlCo
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::foldICmpShlCo
}
}
- 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.
Modified: llvm/trunk/test/Transforms/InstCombine/icmp-shl-nsw.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-shl-nsw.ll?rev=292492&r1=292491&r2=292492&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-shl-nsw.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-shl-nsw.ll Thu Jan 19 10:12:10 2017
@@ -73,8 +73,7 @@ define <2 x i1> @icmp_shl_nsw_eq_vec(<2
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>
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
More information about the llvm-commits
mailing list