forked from OSchip/llvm-project
[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:
parent
08df246407
commit
291c3d8ff2
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue