diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h --- a/llvm/include/llvm/Analysis/ScalarEvolution.h +++ b/llvm/include/llvm/Analysis/ScalarEvolution.h @@ -1898,6 +1898,15 @@ const SCEV *FoundLHS, const SCEV *FoundRHS, unsigned Depth); + /// Test whether the condition described by Pred, LHS, and RHS is true + /// whenever the condition described by Pred, FoundLHS, and FoundRHS is + /// true. + /// + /// This routine tries to reason about shifts. + bool isImpliedCondOperandsViaShift(ICmpInst::Predicate Pred, const SCEV *LHS, + const SCEV *RHS, const SCEV *FoundLHS, + const SCEV *FoundRHS); + /// If we know that the specified Phi is in the header of its containing /// loop, we know the loop executes a constant number of times, and the PHI /// node is just a recurrence involving constants, fold it. diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -11468,6 +11468,48 @@ return true; } +bool ScalarEvolution::isImpliedCondOperandsViaShift(ICmpInst::Predicate Pred, + const SCEV *LHS, + const SCEV *RHS, + const SCEV *FoundLHS, + const SCEV *FoundRHS) { + // We want to imply LHS < RHS from LHS < (RHS >> shiftvalue). First, make + // sure that we are dealing with same LHS. + if (RHS == FoundRHS) { + std::swap(LHS, RHS); + std::swap(FoundLHS, FoundRHS); + Pred = ICmpInst::getSwappedPredicate(Pred); + } + if (LHS != FoundLHS) + return false; + + auto *SUFoundRHS = dyn_cast(FoundRHS); + if (!SUFoundRHS) + return false; + + Value *Shiftee, *ShiftValue; + + using namespace PatternMatch; + if (match(SUFoundRHS->getValue(), + m_LShr(m_Value(Shiftee), m_Value(ShiftValue)))) { + auto *ShifteeS = getSCEV(Shiftee); + // Prove one of the following: + // LHS > shiftvalue) && shiftee <=u RHS ---> LHS > shiftvalue) && shiftee <=u RHS ---> LHS <=u RHS + // LHS > shiftvalue) && shiftee <=s RHS && shiftee >=s 0 + // ---> LHS > shiftvalue) && shiftee <=s RHS && shiftee >=s 0 + // ---> LHS <=s RHS + if (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_ULE) + return isKnownPredicate(ICmpInst::ICMP_ULE, ShifteeS, RHS); + if (Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SLE) + if (isKnownNonNegative(ShifteeS)) + return isKnownPredicate(ICmpInst::ICMP_SLE, ShifteeS, RHS); + } + + return false; +} + bool ScalarEvolution::isImpliedCondOperands(ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS, const SCEV *FoundLHS, @@ -11479,6 +11521,9 @@ if (isImpliedCondOperandsViaNoOverflow(Pred, LHS, RHS, FoundLHS, FoundRHS)) return true; + if (isImpliedCondOperandsViaShift(Pred, LHS, RHS, FoundLHS, FoundRHS)) + return true; + if (isImpliedCondOperandsViaAddRecStart(Pred, LHS, RHS, FoundLHS, FoundRHS, CtxI)) return true; diff --git a/llvm/test/Transforms/IndVarSimplify/shift-range-checks.ll b/llvm/test/Transforms/IndVarSimplify/shift-range-checks.ll --- a/llvm/test/Transforms/IndVarSimplify/shift-range-checks.ll +++ b/llvm/test/Transforms/IndVarSimplify/shift-range-checks.ll @@ -5,8 +5,6 @@ declare i1 @cond() declare void @exit(i32 %code) -; FIXME: We can remove 2nd check here because it is implied by check -; against the shifted value. define void @test_01(i32* %p, i32 %shift) { ; CHECK-LABEL: @test_01( ; CHECK-NEXT: entry: @@ -18,8 +16,7 @@ ; CHECK-NEXT: [[LESS_THAN_SHIFTED:%.*]] = icmp slt i32 [[IV]], [[X_SHIFTED]] ; CHECK-NEXT: br i1 [[LESS_THAN_SHIFTED]], label [[GUARDED:%.*]], label [[FAILURE:%.*]] ; CHECK: guarded: -; CHECK-NEXT: [[LESS_THAN_X:%.*]] = icmp ult i32 [[IV]], [[X]] -; CHECK-NEXT: br i1 [[LESS_THAN_X]], label [[BACKEDGE]], label [[NEVER_HAPPENS:%.*]] +; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[NEVER_HAPPENS:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: [[LOOP_COND:%.*]] = call i1 @cond() @@ -64,8 +61,6 @@ unreachable } -; FIXME: We can remove 2nd check here because it is implied by check -; against the shifted value. define void @test_02(i32* %p, i32 %shift) { ; CHECK-LABEL: @test_02( ; CHECK-NEXT: entry: @@ -77,8 +72,7 @@ ; CHECK-NEXT: [[LESS_THAN_SHIFTED:%.*]] = icmp sgt i32 [[X_SHIFTED]], [[IV]] ; CHECK-NEXT: br i1 [[LESS_THAN_SHIFTED]], label [[GUARDED:%.*]], label [[FAILURE:%.*]] ; CHECK: guarded: -; CHECK-NEXT: [[LESS_THAN_X:%.*]] = icmp ugt i32 [[X]], [[IV]] -; CHECK-NEXT: br i1 [[LESS_THAN_X]], label [[BACKEDGE]], label [[NEVER_HAPPENS:%.*]] +; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[NEVER_HAPPENS:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: [[LOOP_COND:%.*]] = call i1 @cond() @@ -123,8 +117,6 @@ unreachable } -; FIXME: We can remove 2nd check here because it is implied by check -; against the shifted value. define void @test_03(i32* %p, i32 %shift) { ; CHECK-LABEL: @test_03( ; CHECK-NEXT: entry: @@ -136,8 +128,7 @@ ; CHECK-NEXT: [[LESS_THAN_SHIFTED:%.*]] = icmp ult i32 [[IV]], [[X_SHIFTED]] ; CHECK-NEXT: br i1 [[LESS_THAN_SHIFTED]], label [[GUARDED:%.*]], label [[FAILURE:%.*]] ; CHECK: guarded: -; CHECK-NEXT: [[LESS_THAN_X:%.*]] = icmp ult i32 [[IV]], [[X]] -; CHECK-NEXT: br i1 [[LESS_THAN_X]], label [[BACKEDGE]], label [[NEVER_HAPPENS:%.*]] +; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[NEVER_HAPPENS:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: [[LOOP_COND:%.*]] = call i1 @cond() @@ -182,8 +173,6 @@ unreachable } -; FIXME: We can remove 2nd check here because it is implied by check -; against the shifted value. define void @test_04(i32* %p, i32 %shift) { ; CHECK-LABEL: @test_04( ; CHECK-NEXT: entry: @@ -195,8 +184,7 @@ ; CHECK-NEXT: [[LESS_THAN_SHIFTED:%.*]] = icmp ugt i32 [[X_SHIFTED]], [[IV]] ; CHECK-NEXT: br i1 [[LESS_THAN_SHIFTED]], label [[GUARDED:%.*]], label [[FAILURE:%.*]] ; CHECK: guarded: -; CHECK-NEXT: [[LESS_THAN_X:%.*]] = icmp ugt i32 [[X]], [[IV]] -; CHECK-NEXT: br i1 [[LESS_THAN_X]], label [[BACKEDGE]], label [[NEVER_HAPPENS:%.*]] +; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[NEVER_HAPPENS:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: [[LOOP_COND:%.*]] = call i1 @cond()