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

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 26 10:04:55 PDT 2019


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


More information about the llvm-commits mailing list