On Mon, Feb 22, 2016 at 03:59:01PM -0800, Mehdi Amini wrote:
> 
> > On Feb 22, 2016, at 3:47 PM, Peter Collingbourne <pe...@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 <pe...@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
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to