[llvm] r251558 - [SCEV] Compute max backedge count for loops with "shift ivs"
Sanjoy Das via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 28 14:51:02 PDT 2015
I decided to do a post-commit review on this. Andy has (in an offline
email) okay'ed me to do post-commit review on SCEV changes.
-- Sanjoy
Sanjoy Das via llvm-commits wrote:
> Author: sanjoy
> Date: Wed Oct 28 16:27:14 2015
> New Revision: 251558
>
> URL: http://llvm.org/viewvc/llvm-project?rev=251558&view=rev
> Log:
> [SCEV] Compute max backedge count for loops with "shift ivs"
>
> This teaches SCEV to compute //max// backedge taken counts for loops
> like
>
> for (int i = k; i != 0; i>>>= 1)
> whatever();
>
> SCEV yet cannot represent the exact backedge count for these loops, and
> this patch does not change that. This is really geared towards teaching
> SCEV that loops like the above are *not* infinite.
>
> Added:
> llvm/trunk/test/Analysis/ScalarEvolution/shift-op.ll
> Modified:
> llvm/trunk/include/llvm/Analysis/ScalarEvolution.h
> llvm/trunk/lib/Analysis/ScalarEvolution.cpp
>
> Modified: llvm/trunk/include/llvm/Analysis/ScalarEvolution.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/ScalarEvolution.h?rev=251558&r1=251557&r2=251558&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/Analysis/ScalarEvolution.h (original)
> +++ llvm/trunk/include/llvm/Analysis/ScalarEvolution.h Wed Oct 28 16:27:14 2015
> @@ -482,6 +482,17 @@ namespace llvm {
> const Loop *L,
> ICmpInst::Predicate p);
>
> + /// Compute the exit limit of a loop that is controlled by a
> + /// "(IV>> 1) != 0" type comparison. We cannot compute the exact trip
> + /// count in these cases (since SCEV has no way of expressing them), but we
> + /// can still sometimes compute an upper bound.
> + ///
> + /// Return an ExitLimit for a loop whose backedge is guarded by `LHS Pred
> + /// RHS`.
> + ExitLimit computeShiftCompareExitLimit(Value *LHS, Value *RHS,
> + const Loop *L,
> + ICmpInst::Predicate Pred);
> +
> /// If the loop is known to execute a constant number of times (the
> /// condition evolves only from constants), try to evaluate a few iterations
> /// of the loop until we get the exit condition gets a value of ExitWhen
>
> Modified: llvm/trunk/lib/Analysis/ScalarEvolution.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ScalarEvolution.cpp?rev=251558&r1=251557&r2=251558&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Analysis/ScalarEvolution.cpp (original)
> +++ llvm/trunk/lib/Analysis/ScalarEvolution.cpp Wed Oct 28 16:27:14 2015
> @@ -83,6 +83,7 @@
> #include "llvm/IR/LLVMContext.h"
> #include "llvm/IR/Metadata.h"
> #include "llvm/IR/Operator.h"
> +#include "llvm/IR/PatternMatch.h"
> #include "llvm/Support/CommandLine.h"
> #include "llvm/Support/Debug.h"
> #include "llvm/Support/ErrorHandling.h"
> @@ -5398,6 +5399,11 @@ ScalarEvolution::computeExitLimitFromICm
> return ItCnt;
> }
>
> + ExitLimit ShiftEL = computeShiftCompareExitLimit(
> + ExitCond->getOperand(0), ExitCond->getOperand(1), L, Cond);
> + if (ShiftEL.hasAnyInfo())
> + return ShiftEL;
> +
> const SCEV *LHS = getSCEV(ExitCond->getOperand(0));
> const SCEV *RHS = getSCEV(ExitCond->getOperand(1));
>
> @@ -5576,6 +5582,149 @@ ScalarEvolution::computeLoadConstantComp
> return getCouldNotCompute();
> }
>
> +ScalarEvolution::ExitLimit ScalarEvolution::computeShiftCompareExitLimit(
> + Value *LHS, Value *RHSV, const Loop *L, ICmpInst::Predicate Pred) {
> + ConstantInt *RHS = dyn_cast<ConstantInt>(RHSV);
> + if (!RHS)
> + return getCouldNotCompute();
> +
> + const BasicBlock *Latch = L->getLoopLatch();
> + if (!Latch)
> + return getCouldNotCompute();
> +
> + const BasicBlock *Predecessor = L->getLoopPredecessor();
> + if (!Predecessor)
> + return getCouldNotCompute();
> +
> + // Return true if V is of the form "LHS `shift_op`<positive constant>".
> + // Return LHS in OutLHS and shift_opt in OutOpCode.
> + auto MatchPositiveShift =
> + [](Value *V, Value *&OutLHS, Instruction::BinaryOps&OutOpCode) {
> +
> + using namespace PatternMatch;
> +
> + ConstantInt *ShiftAmt;
> + if (match(V, m_LShr(m_Value(OutLHS), m_ConstantInt(ShiftAmt))))
> + OutOpCode = Instruction::LShr;
> + else if (match(V, m_AShr(m_Value(OutLHS), m_ConstantInt(ShiftAmt))))
> + OutOpCode = Instruction::AShr;
> + else if (match(V, m_Shl(m_Value(OutLHS), m_ConstantInt(ShiftAmt))))
> + OutOpCode = Instruction::Shl;
> + else
> + return false;
> +
> + return ShiftAmt->getValue().isStrictlyPositive();
> + };
> +
> + // Recognize a "shift recurrence" either of the form %iv or of %iv.shifted in
> + //
> + // loop:
> + // %iv = phi i32 [ %iv.shifted, %loop ], [ %val, %preheader ]
> + // %iv.shifted = lshr i32 %iv,<positive constant>
> + //
> + // Return true on a succesful match. Return the corresponding PHI node (%iv
> + // above) in PNOut and the opcode of the shift operation in OpCodeOut.
> + auto MatchShiftRecurrence =
> + [&](Value *V, PHINode *&PNOut, Instruction::BinaryOps&OpCodeOut) {
> + Optional<Instruction::BinaryOps> PostShiftOpCode;
> +
> + {
> + Instruction::BinaryOps OpC;
> + Value *V;
> +
> + // If we encounter a shift instruction, "peel off" the shift operation,
> + // and remember that we did so. Later when we inspect %iv's backedge
> + // value, we will make sure that the backedge value uses the same
> + // operation.
> + //
> + // Note: the peeled shift operation does not have to be the same
> + // instruction as the one feeding into the PHI's backedge value. We only
> + // really care about it being the same *kind* of shift instruction --
> + // that's all that is required for our later inferences to hold.
> + if (MatchPositiveShift(LHS, V, OpC)) {
> + PostShiftOpCode = OpC;
> + LHS = V;
> + }
> + }
> +
> + PNOut = dyn_cast<PHINode>(LHS);
> + if (!PNOut || PNOut->getParent() != L->getHeader())
> + return false;
> +
> + Value *BEValue = PNOut->getIncomingValueForBlock(Latch);
> + Value *OpLHS;
> +
> + return
> + // The backedge value for the PHI node must be a shift by a positive
> + // amount
> + MatchPositiveShift(BEValue, OpLHS, OpCodeOut)&&
> +
> + // of the PHI node itself
> + OpLHS == PNOut&&
> +
> + // and the kind of shift should be match the kind of shift we peeled
> + // off, if any.
> + (!PostShiftOpCode.hasValue() || *PostShiftOpCode == OpCodeOut);
> + };
> +
> + PHINode *PN;
> + Instruction::BinaryOps OpCode;
> + if (!MatchShiftRecurrence(LHS, PN, OpCode))
> + return getCouldNotCompute();
> +
> + const DataLayout&DL = getDataLayout();
> +
> + // The key rationale for this optimization is that for some kinds of shift
> + // recurrences, the value of the recurrence "stabilizes" to either 0 or -1
> + // within a finite number of iterations. If the condition guarding the
> + // backedge (in the sense that the backedge is taken if the condition is true)
> + // is false for the value the shift recurrence stabilizes to, then we know
> + // that the backedge is taken only a finite number of times.
> +
> + ConstantInt *StableValue = nullptr;
> + switch (OpCode) {
> + default:
> + llvm_unreachable("Impossible case!");
> +
> + case Instruction::AShr: {
> + // {K,ashr,<positive-constant>} stabilizes to signum(K) in at most
> + // bitwidth(K) iterations.
> + Value *FirstValue = PN->getIncomingValueForBlock(Predecessor);
> + bool KnownZero, KnownOne;
> + ComputeSignBit(FirstValue, KnownZero, KnownOne, DL, 0, nullptr,
> + Predecessor->getTerminator(),&DT);
> + auto *Ty = cast<IntegerType>(RHS->getType());
> + if (KnownZero)
> + StableValue = ConstantInt::get(Ty, 0);
> + else if (KnownOne)
> + StableValue = ConstantInt::get(Ty, -1, true);
> + else
> + return getCouldNotCompute();
> +
> + break;
> + }
> + case Instruction::LShr:
> + case Instruction::Shl:
> + // Both {K,lshr,<positive-constant>} and {K,shl,<positive-constant>}
> + // stabilize to 0 in at most bitwidth(K) iterations.
> + StableValue = ConstantInt::get(cast<IntegerType>(RHS->getType()), 0);
> + break;
> + }
> +
> + auto *Result =
> + ConstantFoldCompareInstOperands(Pred, StableValue, RHS, DL,&TLI);
> + assert(Result->getType()->isIntegerTy(1)&&
> + "Otherwise cannot be an operand to a branch instruction");
> +
> + if (Result->isZeroValue()) {
> + unsigned BitWidth = getTypeSizeInBits(RHS->getType());
> + const SCEV *UpperBound =
> + getConstant(getEffectiveSCEVType(RHS->getType()), BitWidth);
> + return ExitLimit(getCouldNotCompute(), UpperBound);
> + }
> +
> + return getCouldNotCompute();
> +}
>
> /// CanConstantFold - Return true if we can constant fold an instruction of the
> /// specified type, assuming that all operands were constants.
>
> Added: llvm/trunk/test/Analysis/ScalarEvolution/shift-op.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/ScalarEvolution/shift-op.ll?rev=251558&view=auto
> ==============================================================================
> --- llvm/trunk/test/Analysis/ScalarEvolution/shift-op.ll (added)
> +++ llvm/trunk/test/Analysis/ScalarEvolution/shift-op.ll Wed Oct 28 16:27:14 2015
> @@ -0,0 +1,164 @@
> +; RUN: opt -analyze -scalar-evolution< %s | FileCheck %s
> +
> +define void @test0(i32 %init) {
> +; CHECK-LABEL: Classifying expressions for: @test0
> +; CHECK: Loop %loop: max backedge-taken count is 32
> + entry:
> + br label %loop
> +
> + loop:
> + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ]
> + %iv.shift = lshr i32 %iv, 1
> + %exit.cond = icmp eq i32 %iv, 0
> + br i1 %exit.cond, label %leave, label %loop
> +
> + leave:
> + ret void
> +}
> +
> +define void @test1(i32 %init) {
> +; CHECK-LABEL: Classifying expressions for: @test1
> +; CHECK: Loop %loop: max backedge-taken count is 32
> + entry:
> + br label %loop
> +
> + loop:
> + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ]
> + %iv.shift = shl i32 %iv, 1
> + %exit.cond = icmp eq i32 %iv, 0
> + br i1 %exit.cond, label %leave, label %loop
> +
> + leave:
> + ret void
> +}
> +
> +define void @test2(i32 %init) {
> +; CHECK-LABEL: Determining loop execution counts for: @test2
> +; CHECK: Loop %loop: Unpredictable max backedge-taken count.
> +
> +; Unpredictable because %iv could "stabilize" to either -1 or 0,
> +; depending on %init.
> + entry:
> + br label %loop
> +
> + loop:
> + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ]
> + %iv.shift = ashr i32 %iv, 1
> + %exit.cond = icmp eq i32 %iv, 0
> + br i1 %exit.cond, label %leave, label %loop
> +
> + leave:
> + ret void
> +}
> +
> +define void @test3(i32* %init.ptr) {
> +; CHECK-LABEL: Determining loop execution counts for: @test3
> +; CHECK: Loop %loop: max backedge-taken count is 32
> + entry:
> + %init = load i32, i32* %init.ptr, !range !0
> + br label %loop
> +
> + loop:
> + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ]
> + %iv.shift = ashr i32 %iv, 1
> + %exit.cond = icmp eq i32 %iv, 0
> + br i1 %exit.cond, label %leave, label %loop
> +
> + leave:
> + ret void
> +}
> +
> +define void @test4(i32* %init.ptr) {
> +; CHECK-LABEL: Classifying expressions for: @test4
> +; CHECK-LABEL: Loop %loop: max backedge-taken count is 32
> + entry:
> + %init = load i32, i32* %init.ptr, !range !1
> + br label %loop
> +
> + loop:
> + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ]
> + %iv.shift = ashr i32 %iv, 1
> + %exit.cond = icmp eq i32 %iv, -1
> + br i1 %exit.cond, label %leave, label %loop
> +
> + leave:
> + ret void
> +}
> +
> +define void @test5(i32* %init.ptr) {
> +; CHECK-LABEL: Determining loop execution counts for: @test5
> +; CHECK: Loop %loop: Unpredictable max backedge-taken count.
> +
> +; %iv will "stabilize" to -1, so this is an infinite loop
> + entry:
> + %init = load i32, i32* %init.ptr, !range !1
> + br label %loop
> +
> + loop:
> + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ]
> + %iv.shift = ashr i32 %iv, 1
> + %exit.cond = icmp eq i32 %iv, 0
> + br i1 %exit.cond, label %leave, label %loop
> +
> + leave:
> + ret void
> +}
> +
> +define void @test6(i32 %init, i32 %shift.amt) {
> +; CHECK-LABEL: Determining loop execution counts for: @test6
> +; CHECK: Loop %loop: Unpredictable max backedge-taken count.
> +
> +; Potentially infinite loop, since %shift.amt could be 0
> + entry:
> + br label %loop
> +
> + loop:
> + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ]
> + %iv.shift = lshr i32 %iv, %shift.amt
> + %exit.cond = icmp eq i32 %iv, 0
> + br i1 %exit.cond, label %leave, label %loop
> +
> + leave:
> + ret void
> +}
> +
> +define void @test7(i32 %init) {
> +; CHECK-LABEL: Classifying expressions for: @test7
> +; CHECK: Loop %loop: max backedge-taken count is 32
> +
> + entry:
> + br label %loop
> +
> + loop:
> + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ]
> + %iv.shift = lshr i32 %iv, 1
> + %exit.cond = icmp eq i32 %iv.shift, 0
> + br i1 %exit.cond, label %leave, label %loop
> +
> + leave:
> + ret void
> +}
> +
> +define void @test8(i32 %init) {
> +; CHECK-LABEL: Classifying expressions for: @test8
> +; CHECK: Loop %loop: Unpredictable max backedge-taken count.
> +
> +; In this test case, %iv.test stabilizes to 127, not -1, so the loop
> +; is infinite.
> +
> + entry:
> + br label %loop
> +
> + loop:
> + %iv = phi i32 [ %init, %entry ], [ %iv.shift, %loop ]
> + %iv.shift = ashr i32 %iv, 1
> + %iv.test = lshr i32 %iv, 1
> + %exit.cond = icmp eq i32 %iv.test, -1
> + br i1 %exit.cond, label %leave, label %loop
> +
> + leave:
> + ret void
> +}
> +
> +!0 = !{i32 0, i32 50000}
> +!1 = !{i32 -5000, i32 -1}
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list