[PATCH] D16821: Add whole-program vtable optimization feature to Clang.

Peter Collingbourne via cfe-commits cfe-commits at lists.llvm.org
Mon Feb 22 16:04:28 PST 2016


On Mon, Feb 22, 2016 at 03:59:01PM -0800, Mehdi Amini wrote:
> 
> > On Feb 22, 2016, at 3:47 PM, Peter Collingbourne <peter at pcc.me.uk> wrote:
> > 
> > On Mon, Feb 22, 2016 at 01:38:27PM -0800, Pete Cooper wrote:
> >> 
> >>> On Feb 22, 2016, at 1:30 PM, Peter Collingbourne <peter at pcc.me.uk> wrote:
> >>> 
> >>> One thing that I'd like to do (and this would help CFI as well) is to specifically recognize cases like this:
> >>> 
> >>> ```
> >>> struct B {
> >>> virtual void vf();
> >>> };
> >>> 
> >>> struct D1 {
> >>> };
> >> I assume you meant D1 : B here?
> > 
> > Yes.
> > 
> >>> 
> >>> struct D2 : B {
> >>> virtual void vf();
> >>> };
> >>> 
> >>> void f(D1 *d) {
> >>> d->vf();
> >>> }
> >>> ```
> >>> 
> >>> In this case I'd like to devirtualize the virtual call in `f()` to `B::vf()`. But because the implicit cast to `B` in `f()` removes the information that `d` cannot be of type `D2`, we cannot eliminate `D2::vf()` as a candidate target (see also `test/cfi/sibling.cpp` in the CFI test suite).
> >>> 
> >>> Although this could possibly be emitted and pattern matched at the IR level, it seems simpler (and would probably catch enough cases) to have Clang look through the implicit cast when IR gen'ing for the call.
> >> So my devirtualizer dealt with this by marking each call site with the most specific class we know of in the hierarchy.  
> >> 
> >> In this case, then class hierarchy would contain the pairs: (B, B), (D1, B), (D2, B).
> >> 
> >> The call site in f() would be tagged with (D1, B) not (B, B).  Then, when we are in the pass, we look at the subclasses from (D1, B), see that there are none (or that none override vf), and devirtualize to B::vf().
> >> 
> >> If that isn’t possible in the current solution (I didn’t check), then it should be easy enough to add.  I certainly don’t think any of the current implementation would be hard to adapt to support this use case.
> > 
> > I think it should be possible to do something along those lines. After looking
> > through the implicit cast we would discover that the most derived type is D1
> > (I guess this is what your implementation is doing?) and perform the check
> > against that class's bitset, but only if the implicit cast did not involve
> > a pointer adjustment.
> 
> The implementation we have (at least the one I have) generates the most precise information directly from the frontend. You have all the informations at the call site in the clang AST when you access the VTable, there is no cast or anything on the way.

This is what the AST dump for my function looks like for my example:

`-FunctionDecl 0x2d05500 <line:12:1, line:14:1> line:12:6 f 'void (struct D1 *)'
  |-ParmVarDecl 0x2d05438 <col:8, col:12> col:12 used d 'struct D1 *'
  `-CompoundStmt 0x2d07740 <col:15, line:14:1>
    `-CXXMemberCallExpr 0x2d05668 <line:13:1, col:7> 'void'
      `-MemberExpr 0x2d05630 <col:1, col:4> '<bound member function type>' ->vf 0x2cb8ce0
        `-ImplicitCastExpr 0x2d07720 <col:1> 'struct B *' <UncheckedDerivedToBase (B)>
          `-ImplicitCastExpr 0x2d05618 <col:1> 'struct D1 *' <LValueToRValue>
            `-DeclRefExpr 0x2d055f0 <col:1> 'struct D1 *' lvalue ParmVar 0x2d05438 'd' 'struct D1 *'

Thanks,
-- 
Peter


More information about the cfe-commits mailing list