[llvm] r372990 - [LoopInfo] Limit the iterations to check whether a loop has dedicated exits

Wei Mi via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 26 11:06:27 PDT 2019


>From the testcase here: https://reviews.llvm.org/F10054736 and the
description about the testcase in https://reviews.llvm.org/D67359, the
problem can simply be exposed by any pass checking hasDedicatedExits.

hasDedicatedExits's complexity is roughtly "number of exits" x "average
number of predecessors of each exit". We can simply increase the
testcase to have about 50000 cases in the switch statement and then running
hasDedicatedExits once for it can take more than 100 seconds.

So there is no caching opportunity in the triggering pass. But you are
right it is possible to cache the exit inside of hasDedicatedExits. I will
try it and will send an update if it works. Thanks for the suggestion!

Wei.

On Thu, Sep 26, 2019 at 10:04 AM Philip Reames <listmail at philipreames.com>
wrote:

> This really doesn't sound like the right fix.
>
> Can you explain a bit about how this was triggered?  There might be
> either a caching opportunity in the triggering pass, or maybe it's time
> to have LoopInfo actually cache the exits rather then re-enumerating
> them each time.
>
> Philip
>
> On 9/26/19 8:36 AM, Wei Mi via llvm-commits wrote:
> > Author: wmi
> > Date: Thu Sep 26 08:36:25 2019
> > New Revision: 372990
> >
> > URL: http://llvm.org/viewvc/llvm-project?rev=372990&view=rev
> > Log:
> > [LoopInfo] Limit the iterations to check whether a loop has dedicated
> exits
> > for extreme large case.
> >
> > We had a case that a single loop which has 4000 exits and the average
> number
> > of predecessors of each exit is > 1000, and we found compiling the case
> spent
> > a significant amount of time on checking whether a loop has dedicated
> exits.
> > This patch adds a limit for the iterations to the check. With the patch,
> the
> > time to compile our testcase reduced from 1000s to 200s (clang release
> build).
> >
> > Differential Revision: https://reviews.llvm.org/D67359
> >
> >
> > Added:
> >
> llvm/trunk/test/Transforms/LICM/loop-max-dedicated-exit-iterations.ll
> > Modified:
> >      llvm/trunk/include/llvm/Analysis/LoopInfo.h
> >      llvm/trunk/include/llvm/Analysis/LoopInfoImpl.h
> >      llvm/trunk/lib/Analysis/LoopInfo.cpp
> >
> > Modified: llvm/trunk/include/llvm/Analysis/LoopInfo.h
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/LoopInfo.h?rev=372990&r1=372989&r2=372990&view=diff
> >
> ==============================================================================
> > --- llvm/trunk/include/llvm/Analysis/LoopInfo.h (original)
> > +++ llvm/trunk/include/llvm/Analysis/LoopInfo.h Thu Sep 26 08:36:25 2019
> > @@ -269,6 +269,9 @@ public:
> >
> >     /// Return true if no exit block for the loop has a predecessor that
> is
> >     /// outside the loop.
> > +  /// Return false if a non-dedicated successor is found or it cannot
> finish
> > +  /// the check within MaxDedicateExitIterations iterations so return
> false
> > +  /// conservatively.
> >     bool hasDedicatedExits() const;
> >
> >     /// Return all unique successor blocks of this loop.
> >
> > Modified: llvm/trunk/include/llvm/Analysis/LoopInfoImpl.h
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/LoopInfoImpl.h?rev=372990&r1=372989&r2=372990&view=diff
> >
> ==============================================================================
> > --- llvm/trunk/include/llvm/Analysis/LoopInfoImpl.h (original)
> > +++ llvm/trunk/include/llvm/Analysis/LoopInfoImpl.h Thu Sep 26 08:36:25
> 2019
> > @@ -23,6 +23,10 @@
> >
> >   namespace llvm {
> >
> > +// Max number of loop iterations to check whether a loop is a dedicated
> > +// exit loop.
> > +extern cl::opt<uint64_t> MaxDedicateExitIterations;
> > +
> >
>  //===----------------------------------------------------------------------===//
> >   // APIs for simple analysis of the loop. See header notes.
> >
> > @@ -87,10 +91,16 @@ bool LoopBase<BlockT, LoopT>::hasDedicat
> >     // within the loop.
> >     SmallVector<BlockT *, 4> ExitBlocks;
> >     getExitBlocks(ExitBlocks);
> > -  for (BlockT *EB : ExitBlocks)
> > -    for (BlockT *Predecessor : children<Inverse<BlockT *>>(EB))
> > +  uint64_t Iterations = 0;
> > +  for (BlockT *EB : ExitBlocks) {
> > +    for (BlockT *Predecessor : children<Inverse<BlockT *>>(EB)) {
> >         if (!contains(Predecessor))
> >           return false;
> > +      Iterations++;
> > +    }
> > +    if (Iterations > MaxDedicateExitIterations)
> > +      return false;
> > +  }
> >     // All the requirements are met.
> >     return true;
> >   }
> >
> > Modified: llvm/trunk/lib/Analysis/LoopInfo.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LoopInfo.cpp?rev=372990&r1=372989&r2=372990&view=diff
> >
> ==============================================================================
> > --- llvm/trunk/lib/Analysis/LoopInfo.cpp (original)
> > +++ llvm/trunk/lib/Analysis/LoopInfo.cpp Thu Sep 26 08:36:25 2019
> > @@ -54,6 +54,13 @@ static cl::opt<bool, true>
> >       VerifyLoopInfoX("verify-loop-info", cl::location(VerifyLoopInfo),
> >                       cl::Hidden, cl::desc("Verify loop info (time
> consuming)"));
> >
> > +namespace llvm {
> > +cl::opt<uint64_t> MaxDedicateExitIterations(
> > +    "max-dedicate-exit-iterations", cl::Hidden, cl::init(100000),
> > +    cl::desc("Max number of loop iterations to check whether a loop is
> a "
> > +             "dedicated exit loop. "));
> > +}
> > +
> >
>  //===----------------------------------------------------------------------===//
> >   // Loop implementation
> >   //
> >
> > Added:
> llvm/trunk/test/Transforms/LICM/loop-max-dedicated-exit-iterations.ll
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LICM/loop-max-dedicated-exit-iterations.ll?rev=372990&view=auto
> >
> ==============================================================================
> > ---
> llvm/trunk/test/Transforms/LICM/loop-max-dedicated-exit-iterations.ll
> (added)
> > +++
> llvm/trunk/test/Transforms/LICM/loop-max-dedicated-exit-iterations.ll Thu
> Sep 26 08:36:25 2019
> > @@ -0,0 +1,102 @@
> > +; RUN: opt -S -licm -max-dedicate-exit-iterations=5 < %s | FileCheck %s
> > +; RUN: opt -S -licm -max-dedicate-exit-iterations=100 < %s | FileCheck
> %s -check-prefixes=SINK
> > +; RUN: opt -S -passes='require<opt-remark-emit>,loop(licm)'
> -max-dedicate-exit-iterations=5 < %s | FileCheck %s
> > +; RUN: opt -S -passes='require<opt-remark-emit>,loop(licm)'
> -max-dedicate-exit-iterations=100 < %s | FileCheck %s -check-prefixes=SINK
> > +; Code sink in LICM requires the loop has dedicated exits. Use code sink
> > +; in LICM to verify max-dedicate-exit-iterations is functioning.
> > +
> > + at _ZL1m = internal global i64 0, align 8
> > + at .str = private unnamed_addr constant [13 x i8] c"hello = %ld\0A\00",
> align 1
> > + at llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{
> i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_2.cc, i8* null }]
> > +
> > +declare dso_local i64 @_Z3goov() local_unnamed_addr #0
> > +
> > +; Function Attrs: argmemonly nounwind willreturn
> > +declare {}* @llvm.invariant.start.p0i8(i64 immarg, i8* nocapture)
> > +
> > +; Function Attrs: uwtable
> > +define dso_local void @_Z3fool(i64 %a) local_unnamed_addr {
> > +entry:
> > +  %cmp18.old.old.old.old.old = icmp slt i64 %a, 5
> > +  %cmp14.old.old.old.old = icmp slt i64 %a, 4
> > +  %cmp10.old.old.old = icmp slt i64 %a, 3
> > +  %cmp6.old.old = icmp slt i64 %a, 2
> > +  %cmp2.old = icmp slt i64 %a, 1
> > +  %cmp = icmp slt i64 %a, 0
> > +; Check load cannot be sinked out of loop when
> max-dedicate-exit-iterations=5
> > +; and hasDedicatedExits return false, so it is hoisted out of loop.
> > +; CHECK: load i64, i64* @_ZL1m, align 8
> > +; CHECK: br label %do.body
> > +; CHECK: do.body:
> > +  br label %do.body
> > +
> > +do.body:                                          ; preds =
> %do.body.backedge, %entry
> > +  %t0 = load i64, i64* @_ZL1m, align 8, !tbaa !2
> > +  %call = tail call i64 @_Z3goov()
> > +  switch i64 %call, label %do.cond [
> > +    i64 0, label %sw.bb
> > +    i64 1, label %sw.bb1
> > +    i64 2, label %sw.bb5
> > +    i64 3, label %sw.bb9
> > +    i64 4, label %sw.bb13
> > +    i64 5, label %sw.bb17
> > +  ]
> > +
> > +sw.bb:                                            ; preds = %do.body
> > +  br i1 %cmp, label %Done, label %do.body.backedge
> > +
> > +sw.bb1:                                           ; preds = %do.body
> > +  br i1 %cmp2.old, label %Done, label %do.body.backedge
> > +
> > +sw.bb5:                                           ; preds = %do.body
> > +  br i1 %cmp6.old.old, label %Done, label %do.body.backedge
> > +
> > +sw.bb9:                                           ; preds = %do.body
> > +  br i1 %cmp10.old.old.old, label %Done, label %do.body.backedge
> > +
> > +sw.bb13:                                          ; preds = %do.body
> > +  br i1 %cmp14.old.old.old.old, label %Done, label %do.body.backedge
> > +
> > +sw.bb17:                                          ; preds = %do.body
> > +  br i1 %cmp18.old.old.old.old.old, label %Done, label %do.body.backedge
> > +
> > +do.cond:                                          ; preds = %do.body
> > +  %cmp21.old.old.old.old.old.old = icmp slt i64 %call, 10000
> > +  br i1 %cmp21.old.old.old.old.old.old, label %do.body.backedge, label
> %Done
> > +
> > +do.body.backedge:                                 ; preds = %do.cond,
> %sw.bb17, %sw.bb13, %sw.bb9, %sw.bb5, %sw.bb1, %sw.bb
> > +  br label %do.body
> > +
> > +Done:                                             ; preds = %sw.bb,
> %sw.bb1, %sw.bb5, %sw.bb9, %sw.bb13, %sw.bb17, %do.cond
> > +; Check load is sinked out of loop when max-dedicate-exit-iterations=100
> > +; and hasDedicatedExits return true.
> > +; SINK: Done:
> > +; SINK: load i64, i64* @_ZL1m, align 8
> > +; SINK-NEXT: tail call {{.*}} @printf
> > +  %call22 = tail call i32 (i8*, ...) @printf(i8* nonnull
> dereferenceable(1) getelementptr inbounds ([13 x i8], [13 x i8]* @.str, i64
> 0, i64 0), i64 %t0)
> > +  ret void
> > +}
> > +
> > +; Function Attrs: nofree nounwind
> > +declare dso_local i32 @printf(i8* nocapture readonly, ...)
> local_unnamed_addr
> > +
> > +; Function Attrs: uwtable
> > +define internal void @_GLOBAL__sub_I_2.cc() section ".text.startup" {
> > +entry:
> > +  %call.i = tail call i64 @_Z3goov()
> > +  store i64 %call.i, i64* @_ZL1m, align 8, !tbaa !2
> > +  %t0 = tail call {}* @llvm.invariant.start.p0i8(i64 8, i8* bitcast
> (i64* @_ZL1m to i8*))
> > +  ret void
> > +}
> > +
> > +attributes #0 = { readonly }
> > +
> > +!llvm.module.flags = !{!0}
> > +!llvm.ident = !{!1}
> > +
> > +!0 = !{i32 1, !"wchar_size", i32 4}
> > +!1 = !{!"clang version 10.0.0 (trunk 372630) (llvm/trunk 372631)"}
> > +!2 = !{!3, !3, i64 0}
> > +!3 = !{!"long", !4, i64 0}
> > +!4 = !{!"omnipotent char", !5, i64 0}
> > +!5 = !{!"Simple C++ TBAA"}
> >
> >
> > _______________________________________________
> > 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/20190926/2120d35d/attachment.html>


More information about the llvm-commits mailing list