[llvm-dev] Intended behavior of CGSCC pass manager.

Xinliang David Li via llvm-dev llvm-dev at lists.llvm.org
Mon Jun 20 13:17:53 PDT 2016


On Sun, Jun 19, 2016 at 12:01 AM, Sanjoy Das <sanjoy at playingwithpointers.com
> wrote:

> Hi David,
>
> Xinliang David Li wrote:
> >>  I believe it is primarily used for ordering the visitation of
> CallSCC's (i.e. SCC's in the "call graph").
> > This is what it can do -- but what benefit does it provide?
>
> One benefit is that once you get to a function F that constructs an
> instance of a class with virtual functions and then calls a virtual
> function on the instance, then the virtual function being called and
> the constructor will have been maximally simplified (F refs the
> constructor, and the constructor refs all the virtual functions), and
> you're more likely to inline the constructor and devirtualize the
> call.  I don't have any real data to back up that this will materially
> help, though.



Sanjoy, this is a good example. The code pattern is basically like this:

Worker(Base *B) {
    B->vCall();
}

Factory::create(Kind K) {
   if (K == ..) return new D1();
   else ...
}

Caller() {
    ..
    Base *B = Factory::create(K, ...);
    Worker(B);
}


The added ordering constraints from Factory::create() node to all virtual
methods in Base's hierarchy ensures that after
1) Factory::create gets inlined to Caller, and
2) Worker(..) method gets inlined to Caller, and
3) newly exposed vcall gets devirtualized

the inliner sees a callee to say D1::vCall which is already simplified.


However, in real applications, what I see is the following pattern (for
instances LLVM's Pass )

Caller() {
    Base *B =  Factory::create(...);
    Stash (B);  // store the object in some container to be retrieved later
  ...
}

SomeTask() {

   Base *B = findObject(...);
   B->vCall(); // do the work
}

Driver() {
     Caller();  // create objects ...
     SomeTask();
}


Set aside the fact that it is usually much harder to do de-viritualization
in this case,   assuming  the virtual call in SomeTask can be
devritualized. What we need is that the virtual functions are processed
before SomeTask node, but this is not guaranteed unless we also model the
call edge ordering imposed by control flow.

However, this is enforcing virtual methods to be processed before their
object's creators. Are there other simpler ways to achieve the effect (if
we have data to justify it)?

David




>
> -- Sanjoy
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160620/18624daa/attachment.html>


More information about the llvm-dev mailing list