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

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 16 11:25:11 PDT 2019


I submitted a speculative fix for this in rL366241, but I'd really 
appreciate someone familiar with the bot extracting IR so that I can 
confirm the diagnosis.

Philip

On 7/15/19 9:34 PM, Amara Emerson wrote:
> 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/
>
> 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 <mailto: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 <mailto: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/20190716/a188ac88/attachment.html>


More information about the llvm-commits mailing list