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)
}
}
- 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.
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
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
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
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
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
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
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
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
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
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
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
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>
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
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
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
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
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
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
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
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
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
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
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
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
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