Index: lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCompares.cpp +++ lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -2008,43 +2008,42 @@ 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(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(); + 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); + assert(ShiftedC.ashr(ShAmtVal) == C && "Missed simplify"); + return new ICmpInst(Pred, X, ConstantInt::get(Shr->getType(), 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; + assert(!C.isMaxSignedValue() && "Missed simplify"); + assert(!(C + 1).shl(ShAmtVal).isMinSignedValue() && "Missed simplify"); + assert((ShiftedC + 1).ashr(ShAmtVal) == (C + 1) && "Missed simplify"); + return new ICmpInst(Pred, X, ConstantInt::get(Shr->getType(), 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); + assert(ShiftedC.lshr(ShAmtVal) == C && "Missed simplify"); + return new ICmpInst(Pred, X, ConstantInt::get(Shr->getType(), 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; + assert((ShiftedC + 1).lshr(ShAmtVal) == (C + 1) && "Missed simplify"); + return new ICmpInst(Pred, X, ConstantInt::get(Shr->getType(), ShiftedC)); + } } + if (!Cmp.isEquality()) + return nullptr; + // Handle equality comparisons of shift-by-constant. // If the comparison constant changes with the shift, the comparison cannot Index: test/Transforms/InstCombine/icmp-shr-lt-gt.ll =================================================================== --- test/Transforms/InstCombine/icmp-shr-lt-gt.ll +++ test/Transforms/InstCombine/icmp-shr-lt-gt.ll @@ -888,8 +888,7 @@ 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 @@ -899,8 +898,7 @@ 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 @@ -910,8 +908,7 @@ 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 @@ -1002,8 +999,7 @@ 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 @@ -1013,8 +1009,7 @@ 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 @@ -1024,8 +1019,7 @@ 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 @@ -1045,8 +1039,7 @@ 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 @@ -1173,8 +1166,7 @@ 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 @@ -1349,8 +1341,7 @@ 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 @@ -1360,8 +1351,7 @@ 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 @@ -1371,8 +1361,7 @@ 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 @@ -1463,8 +1452,7 @@ 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 @@ -1474,8 +1462,7 @@ 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 @@ -1485,8 +1472,7 @@ 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 @@ -1506,8 +1492,7 @@ 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 @@ -1634,8 +1619,7 @@ 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