<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">Hi,<div class=""><div><br class=""></div><div>David:</div><div>Good point, it will be interesting to see speculative compilation in this context applying on devirtualization, with high level (type) information if applicable.</div><div><br class=""><blockquote type="cite" class=""><div class="">On Mar 28, 2019, at 2:35 PM, preejackie <<a href="mailto:praveenvelliengiri@gmail.com" class="">praveenvelliengiri@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class="">
  
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" class="">
  
  <div bgcolor="#FFFFFF" text="#000000" class=""><p class=""><font face="Courier New, Courier, monospace" class="">Hi David &
        Bekket,</font></p><p class=""><font face="Courier New, Courier, monospace" class="">Thanks your replies
        :) </font></p></div></div></blockquote><blockquote type="cite" class=""><div class=""><div bgcolor="#FFFFFF" text="#000000" class=""><p class=""><font face="Courier New, Courier, monospace" class="">
      </font></p><p class=""><font face="Courier New, Courier, monospace" class="">David, Indent here
        is: ORC v2 JIT APIs has initial(basic) support for concurrent
        compilation in background compile threads. This means we can
        speculatively compile functions before they are even referenced
        by the clients. In future, if the client refer some function and
        if that function is already compiled speculatively we can just
        return the address of function, if this is correctly done we can
        reduce the JIT compilation latencies. IMO, the possible
        candidates to speculate(functions) are those which will be
        executed next. We can use <b class="">program analysis and dynamic
          profiling</b> to find such functions.</font></p><p class=""><font face="Courier New, Courier, monospace" class="">Three possible
        approaches are possible:</font></p>
    <ol class="">
      <li class=""><font face="Courier New, Courier, monospace" class="">Based, on
          analysis from call graphs select functions to compile
          speculatively with less aggressive optimization flags in
          background dedicated compiler threads.</font></li>
      <li class=""><font face="Courier New, Courier, monospace" class="">Since it is a
          JIT, with the help of dynamic profiling we can find frequently
          executed functions and <b class="">re</b>compile them with more
          aggressive optimization in compile thread.</font></li>
      <li class=""><font face="Courier New, Courier, monospace" class="">With
          Profile-guide optimization results of previous executions, we
          can find function that are likely to compile next then <b class="">compile
            it with aggressive optimization. </b>[PGOs are app
          dependent] <br class="">
        </font></li>
    </ol><p class=""><font face="Courier New, Courier, monospace" class="">for cases 1,2:
        profile guide optimization results are not used. I hope these
        techniques collectively improve program execution time in
        long-time. Of course, program-based prediction is not equal to
        the accuracy of profile-based prediction, but in JIT it is
        useful to first compile function speculatively by using multiple
        threads.<br class=""></font></p></div></div></blockquote>I’m a little bit lost, from what I’m understanding, you’re arguing that with the profiling data (collected from runtime), we can make more precise prediction about callee candidates executed next. But in the baseline(i.e. first-time execution) stage, these profile data doesn’t exist, thus you want improve the prediction at that stage with the help of some static analysis.</div><div>Am I understanding correctly?<br class=""><blockquote type="cite" class=""><div class=""><div bgcolor="#FFFFFF" text="#000000" class=""><p class=""><font face="Courier New, Courier, monospace" class="">
      </font></p><p class=""><font face="Courier New, Courier, monospace" class="">I have considered
        CFG as a higher level program representation, I maybe wrong
        here.<br class="">
      </font></p><p class=""><font face="Courier New, Courier, monospace" class="">For example: <br class="">
      </font></p><p class=""><font face="Courier New, Courier, monospace" class=""><code class="">void f2() {} <br class="">
        </code></font></p><p class=""><font face="Courier New, Courier, monospace" class=""><code class="">void f3() {}</code></font></p><p class=""><font face="Courier New, Courier, monospace" class=""><code class="">void  z(){</code></font></p><p class=""><font face="Courier New, Courier, monospace" class=""><code class="">if(/some
          condition/) <br class="">
        </code></font></p><p class=""><font face="Courier New, Courier, monospace" class=""><code class=""> f2();f3();</code></font></p><p class=""><font face="Courier New, Courier, monospace" class=""><code class="">else <br class="">
        </code></font></p><p class=""><font face="Courier New, Courier, monospace" class=""><code class="">fn();</code></font></p><p class=""><font face="Courier New, Courier, monospace" class=""><code class="">}<br class="">
        </code></font></p><p class=""><font face="Courier New, Courier, monospace" class="">Follow the control
        flow of z and compute probability that one of the paths[entry to
        exit] within the z that lead to a call f2, if the call to f2
        occurs in many paths, then the probability that it will execute
        next is high. It will require some control flow analysis. <br class=""></font></p></div></div></blockquote>Following my comment above, I think you have some misunderstandings on the power of static analysis in LLVM: LLVM of course can eliminate some trivial control flow structure like </div><div>if(true) {</div><div> // do something</div><div>}</div><div>Or</div><div>if(1 + 2 < 6)</div><div>For these cases, you don’t even need to analyze the probability of those branches, cause LLVM will just eliminate and optimize the entire control structures.</div><div><br class=""></div><div>But other than that, it’s really hard for LLVM to evaluate the probability of certain branches statically without help from (dynamic) data like profiling data or certain programmer’s annotations like __builtin_expect. </div><div>The closest analysis I can come up with are probably LazyValueInfo and ScalarEvolution. You can see if they fit your need.</div><div><br class=""></div><div>Best,</div><div>Bekket </div><div><blockquote type="cite" class=""><div class=""><div bgcolor="#FFFFFF" text="#000000" class=""><p class=""><font face="Courier New, Courier, monospace" class="">
      </font></p><p class="">Challenges: <br class="">
    </p>
    <ol class="">
      <li class="">   To incorporate speculation in ORC v2.</li>
      <li class="">   Making speculative decisions faster, hence I decide to use
        simple heuristics. </li>
    </ol><p class="">If you need more information / or feeling I'm missing something,
      Please leave a reply :) <br class="">
    </p>
    <div class="moz-cite-prefix">On 29/03/19 12:27 AM, David Greene
      wrote:<br class="">
    </div>
    <blockquote type="cite" cite="mid:nngva026d46.fsf@cray.com" class="">
      <pre class="moz-quote-pre" wrap="">Devirtualization is an example of predicting calls and is much more
easily done on a higher-level representation.  It is simply easier to
reason about certain things given information that is lost during
translation to LLVM IR.  The MLIR project makes similar arguments.

It would be helpful to know what's being attempted here.  I'm not sure
what the (hardware?) branch predictor has to do with making decisions
based compile-time information, unless some kind of PGO is being used.
I could imagine something that takes branch probabilities and guesses
the most likely path through a function, thus predicting certain calls
will happen over others.

                    -David

Bekket McClane via llvm-dev <a class="moz-txt-link-rfc2396E" href="mailto:llvm-dev@lists.llvm.org"><llvm-dev@lists.llvm.org></a> writes:

</pre>
      <blockquote type="cite" class="">
        <pre class="moz-quote-pre" wrap="">Hi PreeJackie,

I still have difficulties associating ‘higher level program analysis’ with the possible candidate functions that will be executed next.
Call graph will definitely be your tools(and actually it’s usually not considered ‘high level’), and function attributes might help. But AFAIC, there is little ‘high level’
language constructions that can help us determinate the possible functions executed next.
Maybe you can give us some examples?

Best,
Bekket

 On Mar 27, 2019, at 8:55 PM, preejackie via llvm-dev <a class="moz-txt-link-rfc2396E" href="mailto:llvm-dev@lists.llvm.org"><llvm-dev@lists.llvm.org></a> wrote:

 Hi all,

 I'm looking for some program analysis techniques which help me to find potential functions to execute next, from the current executing function. I want to
 decision based on compile time information. I consider LLVM IR is too low-level to make such analysis. So, I using call graph representation of module. I
 figured out the probability of function which execute next based on the branch predictor, Call instruction distance from the entry of function. I believe that
 many attributes can be derived from higher level program representation. Is there any similar work done like this? LLVM already support analysis for this?
</pre>
      </blockquote>
    </blockquote>
    <pre class="moz-signature" cols="72">-- 
Have a great day!
PreeJackie</pre>
  </div>

</div></blockquote></div><br class=""></div></body></html>