<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Sat, Oct 5, 2013 at 6:53 PM, Hal Finkel <span dir="ltr"><<a href="mailto:hfinkel@anl.gov" target="_blank">hfinkel@anl.gov</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class=""><div class="h5"><br>
----- Nick Lewycky <<a href="mailto:nicholas@mxc.ca">nicholas@mxc.ca</a>> wrote:<br>
> Hal Finkel wrote:<br>
> > ----- Original Message -----<br>
> >> Hal Finkel wrote:<br>
> >>> ----- Original Message -----<br>
> >>>> (I am not on the list)<br>
> >>>><br>
> >>>>> This adds a new optimization pass that can 'promote' malloc'd<br>
> >>>>> memory to<br>
> >>>>> stack-allocated memory when the lifetime of the allocation can be<br>
> >>>>> determined to be bounded by the execution of the function.<br>
> >>>>><br>
> >>>>> To be specific, consider the following three cases:<br>
> >>>>><br>
> >>>>> void bar(int *x);<br>
> >>>>><br>
> >>>>> void foo1() {<br>
> >>>>> int *x = malloc(16);<br>
> >>>>> bar(x);<br>
> >>>>> free(x);<br>
> >>>>> }<br>
> >>>>><br>
> >>>>> In this case the malloc can be replaced by an alloca, and the<br>
> >>>>> free<br>
> >>>>> removed. Note that this is true even though the pointer 'x' is<br>
> >>>>> definitely<br>
> >>>>> captured (and may be recorded in global storage, etc.).<br>
> >>>><br>
> >>>> Hello,<br>
> >>>><br>
> >>>> this seems to rely on the fact that 'bar' returns normally, and<br>
> >>>> thus<br>
> >>>> that<br>
> >>>> whenever malloc is executed, free will be as well. However, bar<br>
> >>>> could<br>
> >>>> never return, or return abnormally by throwing an exception which<br>
> >>>> will<br>
> >>>> skip the call to free.<br>
> >>>><br>
> >>>> void bar(int *x) {<br>
> >>>> free(x);<br>
> >>>> throw 42;<br>
> >>>> }<br>
> >>>><br>
> >>>> will result in calling free on the stack. Now if there was a<br>
> >>>> destructor<br>
> >>>> calling free in foo1... Do you actually also consider exceptions<br>
> >>>> when<br>
> >>>> you<br>
> >>>> test that all paths from malloc to the exits contain a call to<br>
> >>>> free?<br>
> >>>> That<br>
> >>>> would only leave noreturn functions.<br>
> >>><br>
> >>> Marc,<br>
> >>><br>
> >>> Thanks!<br>
> >>><br>
> >>> My understanding is that the extra control-flow from exception<br>
> >>> handling should be accounted for by the basic-block<br>
> >>> successor/predecessor information (because calling a function that<br>
> >>> might throw uses invoke, and then you see both the regular<br>
> >>> predecessor and the cleanup block as predecessors).<br>
> >><br>
> >> No, that's only true if the caller handles the extra control-flow. If<br>
> >> you call (not invoke) a function, and the callee throws, then the<br>
> >> exception propagates out of the caller, going up the stack until it<br>
> >> hits<br>
> >> the function that did use invoke.<br>
> >><br>
> >> Better is to check "nounwind". However, that is also not sufficient,<br>
> >> because in llvm nounwind functions may call longjmp.<br>
> >><br>
> >> I'll double-check that's correct. Also, you're right, I should<br>
> >> check<br>
> >> the function's does-not-return attribute also.<br>
> >><br>
> >> A function which is marked 'noreturn' is guaranteed to never return.<br>
> >> A<br>
> >> function not marked 'noreturn' may also not return -- it may<br>
> >> terminate<br>
> >> the program, longjmp, throw an exception, or loop infinitely.<br>
> ><br>
> > It looks like I could use your 'halting' attribute. What's the status on that?<br>
><br>
> I'm not working on it.<br>
><br>
> There's an infrastructure problem in LLVM that makes this hard. You want<br>
> to use the function analyses and the call graph analysis for SCCs.<br>
> Logically this fits into a CGSCC pass but you can't put it there because<br>
> those can't depend on function passes. Your options are to either make<br>
> the whole thing a module pass (bad, doesn't get interwoven as part of<br>
> the inliner run) or to have the CGSCC pass depend on a really hokey<br>
> module pass which uses the function pass.<br>
><br>
> This is the same problem Chandler is fixing with his PassManager<br>
> rewrite, with the goal of letting the inliner use the function passes.<br>
><br>
> Also, the "is there a loop local to this function" detection in my patch<br>
> is wrong, it was detecting presence of natural loops, not presence of<br>
> backedges.<br>
<br>
</div></div>Do you know how your loop detection could be fixed?</blockquote><div><br></div><div>Detect irreducible loops :)<br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
 Would it be sufficient to check that all backedges in the function had an associated Loop, and if any did not, return a conservative answer?<br></blockquote><div><br>This would work.   If you want a little better, you can also use SCC based approaches to detecting irreducible loops (see GCC's mark_irreducible_loops), or DJ-graph based approaches (augmented dominator trees).    They should produce exactly equivalent results, last i looked.</div>
<div><br></div><div>They should also properly find all loops, both reducible and irreducible.</div><div><br></div><div>Neither  are particularly difficult to implement.</div><div><a href="http://moss.csc.ncsu.edu/~mueller/ftp/pub/mueller/papers/toplas2184.pdf">http://moss.csc.ncsu.edu/~mueller/ftp/pub/mueller/papers/toplas2184.pdf</a> (see part 5) for the dj-graph version (which you could easily modify to not make not require an explicit dj graph structure, LLVM has all the info anyway)</div>
<div><br></div><div>GCC's is a little less documented, because Zdenek, who implemented it, is a graph expert, but if you read the paper first, you can see both approaches really do the same thing.</div><div><br></div>
<div>I have no concept of how often irreducible loops still occur in real code in a way that really matters for your analysis, so i can't opine on whether this is worth the time vs your suggested solution :)<br><br></div>
<div>--Dan</div><div> </div></div></div></div>