3 ms·
Something that surprised me: Compilers happily optimize pointer to member function calls out if it knows definitely what the pointer points to, but not if the p
by jchw 6y ago
Something that surprised me: Compilers happily optimize pointer to member function calls out if it knows definitely what the pointer points to, but not if the pointer is to a virtual function. Recently figured that out thanks to a slightly related debate on whether it would optimize the first case at all - which I thought it would - but I’m surprised by the second case, since it’s not like there’s a virtual dispatch to worry about once you’ve already taken a reference - you’re already specifying exactly which one implementation you want. Just one of many nuggets learned from Godbolt: apparently marking a function virtual can kill optimizations even in cases where it seems like it shouldn’t.
- asymptotically2 6y agoTry making your class final. Then it won't bother looking up the address of the virtual function in cases where it knows which class it is.
- KMag 6y agoWhere's your point of confusion? There's still virtual dispatch going on with a pointer to virtual member function... they're typically implemented as fat pointers containing the vtable offset, and calling via the pointer still does virtual dispatch. An alternative would be for the compiler to generate a stub function (can be shared across all classes for cases where the same vtable offset is used, unless your architecture has some very exotic calling convention) that jumps to a fixed offset in the vitable, and use a skinny pointer to that stub as a virtual member function pointer, but that's not the usual implementation. In any case, calling through a pointer to virtual member function has to perform virtual dispatch unless the compiler can statically constrain the runtime type of *this being used at the call site. Remember that C++ needs to allow separate compilation, so without a full-program optimizer that breaks dlopen(), C++ can't perform devirtualization on non-final classes. Making the class final will allow the compiler to statically constrain the runtime type and devirtualize the pointer to member function call. Edit: added paragraph break.
- jchw 6y agoAhhh, nevermind. I was under the impression that when you grabbed a pointer to member function, it was grabbing a specific implementation. I actually did not know it supported virtual dispatch. Now I think I finally understand why MSVC pointer to member functions are 16 bytes wide; I knew about the multi-inheritance this pointer adjustment, but I actually had no idea about virtual dispatch through member pointers. Frankly, I never used them in a way that would’ve mattered for this.
- pjmlp 6y agoThey can optimize pointer to a virtual function, but they need PGO data for doing it. The problem is that most devs don't bother with PGO.
- jchw 6y agoUnfortunately I am too late to edit, but actually I simply misunderstood that the member function pointer would do dynamic dispatch. Somehow after all of these years, I never used that feature. (Although it explains some of the extra bytes needed in a member to function pointer; prior to now I was only aware of the this pointer offset part.)
- saagarjha 6y agoIn the absence of PGO data, some compilers nonetheless will speculate the target of a virtual function call and optimize as such.
- brandmeyer 6y agoI've seen devirtualization happen with link-time optimization as well.