diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 542a1c82b127a..49200d02ef339 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -2414,14 +2414,34 @@ Instruction *InstCombinerImpl::foldICmpShlConstant(ICmpInst &Cmp, // free on the target. It has the additional benefit of comparing to a // smaller constant that may be more target-friendly. unsigned Amt = ShiftAmt->getLimitedValue(TypeBits - 1); - if (Shl->hasOneUse() && Amt != 0 && C.countr_zero() >= Amt && - DL.isLegalInteger(TypeBits - Amt)) { - Type *TruncTy = IntegerType::get(Cmp.getContext(), TypeBits - Amt); - if (auto *ShVTy = dyn_cast(ShType)) - TruncTy = VectorType::get(TruncTy, ShVTy->getElementCount()); - Constant *NewC = - ConstantInt::get(TruncTy, C.ashr(*ShiftAmt).trunc(TypeBits - Amt)); - return new ICmpInst(Pred, Builder.CreateTrunc(X, TruncTy), NewC); + if (Shl->hasOneUse() && Amt != 0 && + shouldChangeType(ShType->getScalarSizeInBits(), TypeBits - Amt)) { + ICmpInst::Predicate CmpPred = Pred; + APInt RHSC = C; + + if (RHSC.countr_zero() < Amt && ICmpInst::isStrictPredicate(CmpPred)) { + // Try the flipped strictness predicate. + // e.g.: + // icmp ult i64 (shl X, 32), 8589934593 -> + // icmp ule i64 (shl X, 32), 8589934592 -> + // icmp ule i32 (trunc X, i32), 2 -> + // icmp ult i32 (trunc X, i32), 3 + if (auto FlippedStrictness = + InstCombiner::getFlippedStrictnessPredicateAndConstant( + Pred, ConstantInt::get(ShType->getContext(), C))) { + CmpPred = FlippedStrictness->first; + RHSC = cast(FlippedStrictness->second)->getValue(); + } + } + + if (RHSC.countr_zero() >= Amt) { + Type *TruncTy = ShType->getWithNewBitWidth(TypeBits - Amt); + Constant *NewC = + ConstantInt::get(TruncTy, RHSC.ashr(*ShiftAmt).trunc(TypeBits - Amt)); + return new ICmpInst( + CmpPred, Builder.CreateTrunc(X, TruncTy, "", Shl->hasNoSignedWrap()), + NewC); + } } return nullptr; diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll index 2d786c8f48833..4dbe2fc88ff71 100644 --- a/llvm/test/Transforms/InstCombine/icmp.ll +++ b/llvm/test/Transforms/InstCombine/icmp.ll @@ -5198,3 +5198,100 @@ define i1 @icmp_freeze_sext(i16 %x, i16 %y) { %cmp2 = icmp uge i16 %ext.fr, %y ret i1 %cmp2 } + +define i1 @test_icmp_shl(i64 %x) { +; CHECK-LABEL: @test_icmp_shl( +; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[X:%.*]] to i32 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], 3 +; CHECK-NEXT: ret i1 [[CMP]] +; + %shl = shl i64 %x, 32 + %cmp = icmp ult i64 %shl, 8589934593 + ret i1 %cmp +} + +define i1 @test_icmp_shl_multiuse(i64 %x) { +; CHECK-LABEL: @test_icmp_shl_multiuse( +; CHECK-NEXT: [[SHL:%.*]] = shl i64 [[X:%.*]], 32 +; CHECK-NEXT: call void @use_i64(i64 [[SHL]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[SHL]], 8589934593 +; CHECK-NEXT: ret i1 [[CMP]] +; + %shl = shl i64 %x, 32 + call void @use_i64(i64 %shl) + %cmp = icmp ult i64 %shl, 8589934593 + ret i1 %cmp +} + +define i1 @test_icmp_shl_illegal_length(i64 %x) { +; CHECK-LABEL: @test_icmp_shl_illegal_length( +; CHECK-NEXT: [[SHL:%.*]] = shl i64 [[X:%.*]], 31 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[SHL]], 8589934593 +; CHECK-NEXT: ret i1 [[CMP]] +; + %shl = shl i64 %x, 31 + %cmp = icmp ult i64 %shl, 8589934593 + ret i1 %cmp +} + +define i1 @test_icmp_shl_invalid_rhsc(i64 %x) { +; CHECK-LABEL: @test_icmp_shl_invalid_rhsc( +; CHECK-NEXT: [[SHL:%.*]] = shl i64 [[X:%.*]], 32 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[SHL]], 8589934595 +; CHECK-NEXT: ret i1 [[CMP]] +; + %shl = shl i64 %x, 32 + %cmp = icmp ult i64 %shl, 8589934595 + ret i1 %cmp +} + +define i1 @test_icmp_shl_nuw(i64 %x) { +; CHECK-LABEL: @test_icmp_shl_nuw( +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[X:%.*]], 3 +; CHECK-NEXT: ret i1 [[CMP]] +; + %shl = shl nuw i64 %x, 32 + %cmp = icmp ult i64 %shl, 8589934593 + ret i1 %cmp +} + +define i1 @test_icmp_shl_nsw(i64 %x) { +; CHECK-LABEL: @test_icmp_shl_nsw( +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[X:%.*]], 3 +; CHECK-NEXT: ret i1 [[CMP]] +; + %shl = shl nsw i64 %x, 32 + %cmp = icmp ult i64 %shl, 8589934593 + ret i1 %cmp +} + +define <2 x i1> @test_icmp_shl_vec(<2 x i64> %x) { +; CHECK-LABEL: @test_icmp_shl_vec( +; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i64> [[X:%.*]] to <2 x i32> +; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i32> [[TMP1]], +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %shl = shl <2 x i64> %x, splat(i64 32) + %cmp = icmp ult <2 x i64> %shl, splat(i64 8589934593) + ret <2 x i1> %cmp +} + +define i1 @test_icmp_shl_eq(i64 %x) { +; CHECK-LABEL: @test_icmp_shl_eq( +; CHECK-NEXT: ret i1 false +; + %shl = shl i64 %x, 32 + %cmp = icmp eq i64 %shl, 8589934593 + ret i1 %cmp +} + +define i1 @test_icmp_shl_sgt(i64 %x) { +; CHECK-LABEL: @test_icmp_shl_sgt( +; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[X:%.*]] to i32 +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP1]], 1 +; CHECK-NEXT: ret i1 [[CMP]] +; + %shl = shl i64 %x, 32 + %cmp = icmp sgt i64 %shl, 8589934591 + ret i1 %cmp +}