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