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