[llvm] r365920 - [IndVars] Use exit count reasoning to discharge obviously untaken exits

Amara Emerson via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 15 21:34:51 PDT 2019


Hi Philip,

This commit looks like (from the assertion, I haven’t bisected it completely) it broke a green dragon ThinLTO stage2 bot: http://green.lab.llvm.org/green/job/clang-stage2-Rthinlto/ <http://green.lab.llvm.org/green/job/clang-stage2-Rthinlto/>

Could you take a look?

Amara

> On Jul 12, 2019, at 10:05 AM, Philip Reames via llvm-commits <llvm-commits at lists.llvm.org> wrote:
> 
> Author: reames
> Date: Fri Jul 12 10:05:35 2019
> New Revision: 365920
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=365920&view=rev
> Log:
> [IndVars] Use exit count reasoning to discharge obviously untaken exits
> 
> Continue in the spirit of D63618, and use exit count reasoning to prove away loop exits which can not be taken since the backedge taken count of the loop as a whole is provably less than the minimal BE count required to take this particular loop exit.
> 
> As demonstrated in the newly added tests, this triggers in a number of cases where IndVars was previously unable to discharge obviously redundant exit tests. And some not so obvious ones.
> 
> Differential Revision: https://reviews.llvm.org/D63733
> 
> 
> Modified:
>    llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp
>    llvm/trunk/test/Transforms/IndVarSimplify/eliminate-exit.ll
> 
> Modified: llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp?rev=365920&r1=365919&r2=365920&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp (original)
> +++ llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp Fri Jul 12 10:05:35 2019
> @@ -144,6 +144,7 @@ class IndVarSimplify {
>   bool rewriteNonIntegerIVs(Loop *L);
> 
>   bool simplifyAndExtend(Loop *L, SCEVExpander &Rewriter, LoopInfo *LI);
> +  bool optimizeLoopExits(Loop *L);
> 
>   bool canLoopBeDeleted(Loop *L, SmallVector<RewritePhi, 8> &RewritePhiSet);
>   bool rewriteLoopExitValues(Loop *L, SCEVExpander &Rewriter);
> @@ -2623,6 +2624,112 @@ bool IndVarSimplify::sinkUnusedInvariant
>   return MadeAnyChanges;
> }
> 
> +bool IndVarSimplify::optimizeLoopExits(Loop *L) {
> +  SmallVector<BasicBlock*, 16> ExitingBlocks;
> +  L->getExitingBlocks(ExitingBlocks);
> +  BasicBlock * const Latch = L->getLoopLatch();
> +
> +  // Form an expression for the maximum exit count possible for this loop. We
> +  // merge the max and exact information to approximate a version of
> +  // getMaxBackedgeTakenInfo which isn't restricted to just constants.
> +  // TODO: factor this out as a version of getMaxBackedgeTakenCount which
> +  // isn't guaranteed to return a constant.
> +  SmallVector<const SCEV*, 4> ExitCounts;
> +  const SCEV *MaxConstEC = SE->getMaxBackedgeTakenCount(L);
> +  if (!isa<SCEVCouldNotCompute>(MaxConstEC))
> +    ExitCounts.push_back(MaxConstEC);
> +  for (BasicBlock *ExitingBB : ExitingBlocks) {
> +    const SCEV *ExitCount = SE->getExitCount(L, ExitingBB);
> +    if (!isa<SCEVCouldNotCompute>(ExitCount)) {
> +      assert(DT->dominates(ExitingBB, Latch) &&
> +             "We should only have known counts for exiting blocks that "
> +             "dominate latch!");
> +      ExitCounts.push_back(ExitCount);
> +    }
> +  }
> +  if (ExitCounts.empty())
> +    return false;
> +  const SCEV *MaxExitCount = SE->getUMinFromMismatchedTypes(ExitCounts);
> +
> +  bool Changed = false;
> +  for (BasicBlock *ExitingBB : ExitingBlocks) {
> +    // If our exitting block exits multiple loops, we can only rewrite the
> +    // innermost one.  Otherwise, we're changing how many times the innermost
> +    // loop runs before it exits. 
> +    if (LI->getLoopFor(ExitingBB) != L)
> +      continue;
> +
> +    // Can't rewrite non-branch yet.
> +    BranchInst *BI = dyn_cast<BranchInst>(ExitingBB->getTerminator());
> +    if (!BI)
> +      continue;
> +
> +    // If already constant, nothing to do.
> +    if (isa<Constant>(BI->getCondition()))
> +      continue;
> +    
> +    const SCEV *ExitCount = SE->getExitCount(L, ExitingBB);
> +    if (isa<SCEVCouldNotCompute>(ExitCount))
> +      continue;
> +
> +    // If we know we'd exit on the first iteration, rewrite the exit to
> +    // reflect this.  This does not imply the loop must exit through this
> +    // exit; there may be an earlier one taken on the first iteration.
> +    // TODO: Given we know the backedge can't be taken, we should go ahead
> +    // and break it.  Or at least, kill all the header phis and simplify.
> +    if (ExitCount->isZero()) {
> +      bool ExitIfTrue = !L->contains(*succ_begin(ExitingBB));
> +      auto *OldCond = BI->getCondition();
> +      auto *NewCond = ExitIfTrue ? ConstantInt::getTrue(OldCond->getType()) :
> +        ConstantInt::getFalse(OldCond->getType());
> +      BI->setCondition(NewCond);
> +      if (OldCond->use_empty())
> +        DeadInsts.push_back(OldCond);
> +      Changed = true;
> +      continue;
> +    }
> +
> +    // If we end up with a pointer exit count, bail.
> +    if (!ExitCount->getType()->isIntegerTy() ||
> +        !MaxExitCount->getType()->isIntegerTy())
> +      return false;
> +    
> +    Type *WiderType =
> +      SE->getWiderType(MaxExitCount->getType(), ExitCount->getType());
> +    ExitCount = SE->getNoopOrZeroExtend(ExitCount, WiderType);
> +    MaxExitCount = SE->getNoopOrZeroExtend(MaxExitCount, WiderType);
> +    assert(MaxExitCount->getType() == ExitCount->getType());
> +    
> +    // Can we prove that some other exit must be taken strictly before this
> +    // one?  TODO: handle cases where ule is known, and equality is covered
> +    // by a dominating exit
> +    if (SE->isLoopEntryGuardedByCond(L, CmpInst::ICMP_ULT,
> +                                     MaxExitCount, ExitCount)) {
> +      bool ExitIfTrue = !L->contains(*succ_begin(ExitingBB));
> +      auto *OldCond = BI->getCondition();
> +      auto *NewCond = ExitIfTrue ? ConstantInt::getFalse(OldCond->getType()) :
> +        ConstantInt::getTrue(OldCond->getType());
> +      BI->setCondition(NewCond);
> +      if (OldCond->use_empty())
> +        DeadInsts.push_back(OldCond);
> +      Changed = true;
> +      continue;
> +    }
> +
> +    // TODO: If we can prove that the exiting iteration is equal to the exit
> +    // count for this exit and that no previous exit oppurtunities exist within
> +    // the loop, then we can discharge all other exits.  (May fall out of
> +    // previous TODO.) 
> +    
> +    // TODO: If we can't prove any relation between our exit count and the
> +    // loops exit count, but taking this exit doesn't require actually running
> +    // the loop (i.e. no side effects, no computed values used in exit), then
> +    // we can replace the exit test with a loop invariant test which exits on
> +    // the first iteration.  
> +  }
> +  return Changed;
> +}
> +
> //===----------------------------------------------------------------------===//
> //  IndVarSimplify driver. Manage several subpasses of IV simplification.
> //===----------------------------------------------------------------------===//
> @@ -2679,6 +2786,8 @@ bool IndVarSimplify::run(Loop *L) {
>   // Eliminate redundant IV cycles.
>   NumElimIV += Rewriter.replaceCongruentIVs(L, DT, DeadInsts);
> 
> +  Changed |= optimizeLoopExits(L);
> +
>   // If we have a trip count expression, rewrite the loop's exit condition
>   // using it.  
>   if (!DisableLFTR) {
> @@ -2702,23 +2811,7 @@ bool IndVarSimplify::run(Loop *L) {
>       if (isa<SCEVCouldNotCompute>(ExitCount))
>         continue;
> 
> -      // If we know we'd exit on the first iteration, rewrite the exit to
> -      // reflect this.  This does not imply the loop must exit through this
> -      // exit; there may be an earlier one taken on the first iteration.
> -      // TODO: Given we know the backedge can't be taken, we should go ahead
> -      // and break it.  Or at least, kill all the header phis and simplify.
> -      if (ExitCount->isZero()) {
> -        auto *BI = cast<BranchInst>(ExitingBB->getTerminator());
> -        bool ExitIfTrue = !L->contains(*succ_begin(ExitingBB));
> -        auto *OldCond = BI->getCondition();
> -        auto *NewCond = ExitIfTrue ? ConstantInt::getTrue(OldCond->getType()) :
> -          ConstantInt::getFalse(OldCond->getType());
> -        BI->setCondition(NewCond);
> -        if (OldCond->use_empty())
> -          DeadInsts.push_back(OldCond);
> -        Changed = true;
> -        continue;
> -      }
> +      assert(!ExitCount->isZero() && "Should have been folded above");
> 
>       PHINode *IndVar = FindLoopCounter(L, ExitingBB, ExitCount, SE, DT);
>       if (!IndVar)
> 
> Modified: llvm/trunk/test/Transforms/IndVarSimplify/eliminate-exit.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/IndVarSimplify/eliminate-exit.ll?rev=365920&r1=365919&r2=365920&view=diff
> ==============================================================================
> --- llvm/trunk/test/Transforms/IndVarSimplify/eliminate-exit.ll (original)
> +++ llvm/trunk/test/Transforms/IndVarSimplify/eliminate-exit.ll Fri Jul 12 10:05:35 2019
> @@ -15,8 +15,7 @@ define void @ult(i64 %n, i64 %m) {
> ; CHECK-NEXT:    br i1 [[CMP1]], label [[LATCH]], label [[EXIT_LOOPEXIT:%.*]]
> ; CHECK:       latch:
> ; CHECK-NEXT:    call void @side_effect()
> -; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i64 [[IV]], [[M]]
> -; CHECK-NEXT:    br i1 [[CMP2]], label [[LOOP]], label [[EXIT_LOOPEXIT]]
> +; CHECK-NEXT:    br i1 true, label [[LOOP]], label [[EXIT_LOOPEXIT]]
> ; CHECK:       exit.loopexit:
> ; CHECK-NEXT:    br label [[EXIT]]
> ; CHECK:       exit:
> @@ -48,8 +47,7 @@ define void @ugt(i64 %n, i64 %m) {
> ; CHECK:       loop:
> ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
> ; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], 1
> -; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i64 [[IV]], [[N]]
> -; CHECK-NEXT:    br i1 [[CMP1]], label [[LATCH]], label [[EXIT_LOOPEXIT:%.*]]
> +; CHECK-NEXT:    br i1 true, label [[LATCH]], label [[EXIT_LOOPEXIT:%.*]]
> ; CHECK:       latch:
> ; CHECK-NEXT:    call void @side_effect()
> ; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i64 [[IV]], [[M]]
> @@ -160,9 +158,7 @@ define void @ult_const_max(i64 %n) {
> ; CHECK:       loop:
> ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
> ; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
> -; CHECK-NEXT:    [[UDIV:%.*]] = udiv i64 [[IV]], 10
> -; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i64 [[UDIV]], 2
> -; CHECK-NEXT:    br i1 [[CMP1]], label [[LATCH]], label [[EXIT_LOOPEXIT:%.*]]
> +; CHECK-NEXT:    br i1 true, label [[LATCH]], label [[EXIT_LOOPEXIT:%.*]]
> ; CHECK:       latch:
> ; CHECK-NEXT:    call void @side_effect()
> ; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i64 [[IV]], [[N]]
> 
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20190715/5e77f75a/attachment.html>


More information about the llvm-commits mailing list