return nullptr;
bool IsAShr = Shr->getOpcode() == Instruction::AShr;
- if (!Cmp.isEquality()) {
- // If we have an unsigned comparison and an ashr, we can't simplify this.
- // Similarly for signed comparisons with lshr.
- if (Cmp.isSigned() != IsAShr)
- return nullptr;
-
- // Otherwise, all lshr and most exact ashr's are equivalent to a udiv/sdiv
- // by a power of 2. Since we already have logic to simplify these,
- // transform to div and then simplify the resultant comparison.
- if (IsAShr && (!Shr->isExact() || ShAmtVal == TypeBits - 1))
- return nullptr;
-
- // Revisit the shift (to delete it).
- Worklist.Add(Shr);
-
- Constant *DivCst = ConstantInt::get(
- Shr->getType(), APInt::getOneBitSet(TypeBits, ShAmtVal));
-
- Value *Tmp = IsAShr ? Builder.CreateSDiv(X, DivCst, "", Shr->isExact())
- : Builder.CreateUDiv(X, DivCst, "", Shr->isExact());
-
- Cmp.setOperand(0, Tmp);
-
- // If the builder folded the binop, just return it.
- BinaryOperator *TheDiv = dyn_cast<BinaryOperator>(Tmp);
- if (!TheDiv)
- return &Cmp;
-
- // Otherwise, fold this div/compare.
- assert(TheDiv->getOpcode() == Instruction::SDiv ||
- TheDiv->getOpcode() == Instruction::UDiv);
-
- Instruction *Res = foldICmpDivConstant(Cmp, TheDiv, C);
- assert(Res && "This div/cst should have folded!");
- return Res;
+ bool IsExact = Shr->isExact();
+ Type *ShrTy = Shr->getType();
+ // TODO: If we could guarantee that InstSimplify would handle all of the
+ // constant-value-based preconditions in the folds below, then we could assert
+ // those conditions rather than checking them. This is difficult because of
+ // undef/poison (PR34838).
+ if (IsAShr) {
+ if (Pred == CmpInst::ICMP_SLT || (Pred == CmpInst::ICMP_SGT && IsExact)) {
+ // icmp slt (ashr X, ShAmtC), C --> icmp slt X, (C << ShAmtC)
+ // icmp sgt (ashr exact X, ShAmtC), C --> icmp sgt X, (C << ShAmtC)
+ APInt ShiftedC = C.shl(ShAmtVal);
+ if (ShiftedC.ashr(ShAmtVal) == C)
+ return new ICmpInst(Pred, X, ConstantInt::get(ShrTy, ShiftedC));
+ }
+ if (Pred == CmpInst::ICMP_SGT) {
+ // icmp sgt (ashr X, ShAmtC), C --> icmp sgt X, ((C + 1) << ShAmtC) - 1
+ APInt ShiftedC = (C + 1).shl(ShAmtVal) - 1;
+ if (!C.isMaxSignedValue() && !(C + 1).shl(ShAmtVal).isMinSignedValue() &&
+ (ShiftedC + 1).ashr(ShAmtVal) == (C + 1))
+ return new ICmpInst(Pred, X, ConstantInt::get(ShrTy, ShiftedC));
+ }
+ } else {
+ if (Pred == CmpInst::ICMP_ULT || (Pred == CmpInst::ICMP_UGT && IsExact)) {
+ // icmp ult (lshr X, ShAmtC), C --> icmp ult X, (C << ShAmtC)
+ // icmp ugt (lshr exact X, ShAmtC), C --> icmp ugt X, (C << ShAmtC)
+ APInt ShiftedC = C.shl(ShAmtVal);
+ if (ShiftedC.lshr(ShAmtVal) == C)
+ return new ICmpInst(Pred, X, ConstantInt::get(ShrTy, ShiftedC));
+ }
+ if (Pred == CmpInst::ICMP_UGT) {
+ // icmp ugt (lshr X, ShAmtC), C --> icmp ugt X, ((C + 1) << ShAmtC) - 1
+ APInt ShiftedC = (C + 1).shl(ShAmtVal) - 1;
+ if ((ShiftedC + 1).lshr(ShAmtVal) == (C + 1))
+ return new ICmpInst(Pred, X, ConstantInt::get(ShrTy, ShiftedC));
+ }
}
+ if (!Cmp.isEquality())
+ return nullptr;
+
// Handle equality comparisons of shift-by-constant.
// If the comparison constant changes with the shift, the comparison cannot
// Check if the bits shifted out are known to be zero. If so, we can compare
// against the unshifted value:
// (X & 4) >> 1 == 2 --> (X & 4) == 4.
- Constant *ShiftedCmpRHS = ConstantInt::get(Shr->getType(), C << ShAmtVal);
+ Constant *ShiftedCmpRHS = ConstantInt::get(ShrTy, C << ShAmtVal);
if (Shr->hasOneUse()) {
if (Shr->isExact())
return new ICmpInst(Pred, X, ShiftedCmpRHS);
// Otherwise strength reduce the shift into an 'and'.
APInt Val(APInt::getHighBitsSet(TypeBits, TypeBits - ShAmtVal));
- Constant *Mask = ConstantInt::get(Shr->getType(), Val);
+ Constant *Mask = ConstantInt::get(ShrTy, Val);
Value *And = Builder.CreateAnd(X, Mask, Shr->getName() + ".mask");
return new ICmpInst(Pred, And, ShiftedCmpRHS);
}
define i1 @ashrsgt_01_00(i4 %x) {
; CHECK-LABEL: @ashrsgt_01_00(
-; CHECK-NEXT: [[S:%.*]] = ashr i4 %x, 1
-; CHECK-NEXT: [[C:%.*]] = icmp sgt i4 [[S]], 0
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i4 %x, 1
; CHECK-NEXT: ret i1 [[C]]
;
%s = ashr i4 %x, 1
define i1 @ashrsgt_01_01(i4 %x) {
; CHECK-LABEL: @ashrsgt_01_01(
-; CHECK-NEXT: [[S:%.*]] = ashr i4 %x, 1
-; CHECK-NEXT: [[C:%.*]] = icmp sgt i4 [[S]], 1
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i4 %x, 3
; CHECK-NEXT: ret i1 [[C]]
;
%s = ashr i4 %x, 1
define i1 @ashrsgt_01_02(i4 %x) {
; CHECK-LABEL: @ashrsgt_01_02(
-; CHECK-NEXT: [[S:%.*]] = ashr i4 %x, 1
-; CHECK-NEXT: [[C:%.*]] = icmp sgt i4 [[S]], 2
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i4 %x, 5
; CHECK-NEXT: ret i1 [[C]]
;
%s = ashr i4 %x, 1
define i1 @ashrsgt_01_12(i4 %x) {
; CHECK-LABEL: @ashrsgt_01_12(
-; CHECK-NEXT: [[S:%.*]] = ashr i4 %x, 1
-; CHECK-NEXT: [[C:%.*]] = icmp sgt i4 [[S]], -4
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i4 %x, -7
; CHECK-NEXT: ret i1 [[C]]
;
%s = ashr i4 %x, 1
define i1 @ashrsgt_01_13(i4 %x) {
; CHECK-LABEL: @ashrsgt_01_13(
-; CHECK-NEXT: [[S:%.*]] = ashr i4 %x, 1
-; CHECK-NEXT: [[C:%.*]] = icmp sgt i4 [[S]], -3
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i4 %x, -5
; CHECK-NEXT: ret i1 [[C]]
;
%s = ashr i4 %x, 1
define i1 @ashrsgt_01_14(i4 %x) {
; CHECK-LABEL: @ashrsgt_01_14(
-; CHECK-NEXT: [[S:%.*]] = ashr i4 %x, 1
-; CHECK-NEXT: [[C:%.*]] = icmp sgt i4 [[S]], -2
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i4 %x, -3
; CHECK-NEXT: ret i1 [[C]]
;
%s = ashr i4 %x, 1
define i1 @ashrsgt_02_00(i4 %x) {
; CHECK-LABEL: @ashrsgt_02_00(
-; CHECK-NEXT: [[S:%.*]] = ashr i4 %x, 2
-; CHECK-NEXT: [[C:%.*]] = icmp sgt i4 [[S]], 0
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i4 %x, 3
; CHECK-NEXT: ret i1 [[C]]
;
%s = ashr i4 %x, 2
define i1 @ashrsgt_02_14(i4 %x) {
; CHECK-LABEL: @ashrsgt_02_14(
-; CHECK-NEXT: [[S:%.*]] = ashr i4 %x, 2
-; CHECK-NEXT: [[C:%.*]] = icmp sgt i4 [[S]], -2
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i4 %x, -5
; CHECK-NEXT: ret i1 [[C]]
;
%s = ashr i4 %x, 2
define i1 @ashrslt_01_01(i4 %x) {
; CHECK-LABEL: @ashrslt_01_01(
-; CHECK-NEXT: [[S:%.*]] = ashr i4 %x, 1
-; CHECK-NEXT: [[C:%.*]] = icmp slt i4 [[S]], 1
+; CHECK-NEXT: [[C:%.*]] = icmp slt i4 %x, 2
; CHECK-NEXT: ret i1 [[C]]
;
%s = ashr i4 %x, 1
define i1 @ashrslt_01_02(i4 %x) {
; CHECK-LABEL: @ashrslt_01_02(
-; CHECK-NEXT: [[S:%.*]] = ashr i4 %x, 1
-; CHECK-NEXT: [[C:%.*]] = icmp slt i4 [[S]], 2
+; CHECK-NEXT: [[C:%.*]] = icmp slt i4 %x, 4
; CHECK-NEXT: ret i1 [[C]]
;
%s = ashr i4 %x, 1
define i1 @ashrslt_01_03(i4 %x) {
; CHECK-LABEL: @ashrslt_01_03(
-; CHECK-NEXT: [[S:%.*]] = ashr i4 %x, 1
-; CHECK-NEXT: [[C:%.*]] = icmp slt i4 [[S]], 3
+; CHECK-NEXT: [[C:%.*]] = icmp slt i4 %x, 6
; CHECK-NEXT: ret i1 [[C]]
;
%s = ashr i4 %x, 1
define i1 @ashrslt_01_13(i4 %x) {
; CHECK-LABEL: @ashrslt_01_13(
-; CHECK-NEXT: [[S:%.*]] = ashr i4 %x, 1
-; CHECK-NEXT: [[C:%.*]] = icmp slt i4 [[S]], -3
+; CHECK-NEXT: [[C:%.*]] = icmp slt i4 %x, -6
; CHECK-NEXT: ret i1 [[C]]
;
%s = ashr i4 %x, 1
define i1 @ashrslt_01_14(i4 %x) {
; CHECK-LABEL: @ashrslt_01_14(
-; CHECK-NEXT: [[S:%.*]] = ashr i4 %x, 1
-; CHECK-NEXT: [[C:%.*]] = icmp slt i4 [[S]], -2
+; CHECK-NEXT: [[C:%.*]] = icmp slt i4 %x, -4
; CHECK-NEXT: ret i1 [[C]]
;
%s = ashr i4 %x, 1
define i1 @ashrslt_01_15(i4 %x) {
; CHECK-LABEL: @ashrslt_01_15(
-; CHECK-NEXT: [[S:%.*]] = ashr i4 %x, 1
-; CHECK-NEXT: [[C:%.*]] = icmp slt i4 [[S]], -1
+; CHECK-NEXT: [[C:%.*]] = icmp slt i4 %x, -2
; CHECK-NEXT: ret i1 [[C]]
;
%s = ashr i4 %x, 1
define i1 @ashrslt_02_01(i4 %x) {
; CHECK-LABEL: @ashrslt_02_01(
-; CHECK-NEXT: [[S:%.*]] = ashr i4 %x, 2
-; CHECK-NEXT: [[C:%.*]] = icmp slt i4 [[S]], 1
+; CHECK-NEXT: [[C:%.*]] = icmp slt i4 %x, 4
; CHECK-NEXT: ret i1 [[C]]
;
%s = ashr i4 %x, 2
define i1 @ashrslt_02_15(i4 %x) {
; CHECK-LABEL: @ashrslt_02_15(
-; CHECK-NEXT: [[S:%.*]] = ashr i4 %x, 2
-; CHECK-NEXT: [[C:%.*]] = icmp slt i4 [[S]], -1
+; CHECK-NEXT: [[C:%.*]] = icmp slt i4 %x, -4
; CHECK-NEXT: ret i1 [[C]]
;
%s = ashr i4 %x, 2