Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call to constant pointer-to-member function not being inlined

Tags:

c++

c++11

Now, I know there are no guarantees for inlining, but...

Given the following:

struct Base {
    virtual int f() = 0;
};

struct Derived : public Base {
    virtual int f() final override {
        return 42;
    }
};

extern Base* b;

We have that:

int main() {
    return static_cast<Derived*>(b)->f();
}

Compiles down to:

main:
    movl    $42, %eax
    ret

Yet...

int main() {
    return (static_cast<Derived*>(b)->*(&Derived::f))();
}

Compiles down to:

main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $16, %esp
    movl    b, %eax
    movl    (%eax), %edx
    movl    %eax, (%esp)
    call    *(%edx)
    leave
    ret

Which is really saddening.

Why is that call to PMF not being inlined? The PMF is a constant expression!

like image 940
Gabriel Garcia Avatar asked Sep 29 '13 15:09

Gabriel Garcia


People also ask

Can function pointers be Inlined?

In Part 2, the virtual function is called through a pointer, so it cannot be inlined.

Can we call member function using this pointer?

You can use pointers to member functions in the same manner as pointers to functions. You can compare pointers to member functions, assign values to them, and use them to call member functions.

Can we call member function using this pointer from constructor?

the constructor is the first function which get called. and we can access the this pointer via constructor for the first time. if we are able to get the this pointer before constructor call (may be via malloc which will not call constructor at all), we can call member function even before constructor call.

How do you declare a pointer to a member function in C++?

Short answer: add a const to the right of the ) when you use a typedef to declare the member-function-pointer type. For example, suppose you want a pointer-to-member-function that points at Fred::f , Fred::g or Fred::h : class Fred {


2 Answers

The problem here is that in the first case type based devirtualization turns the indirect call into a direct call. When you add a member pointer, type based devirtualization can not be used (since it works by frontend passing down to optimization information about type and virtual method being called that is not trivially known from the in this case). GCC may be able to constant fold the actual access into virutal table by knowing that B is a class and knowing that its member can be called only after it has been constructed. At the moment it don't do such analysis.

I would suggest filling in enhancement request to GCC bugzilla.

like image 191
Jan Hubička Avatar answered Oct 16 '22 10:10

Jan Hubička


It is not always possible to inline pointer to function (unless the compiler is able to figure out what the pointer is actually pointing at, which is often difficult, so the compiler may "give up" before you expect it to).

EDIT

To expand on my answer: The first priority in all compilers is to generate CORRECT code (although sometimes this doesn't happen either!). Optimisation, such as inlining functions, is something the compiler will only do when "it is safe". The compiler may not quite "understand" that the above expression is indeed a constant expression, and therefore fall back to "let's do the safe thing" (which is to call via the virtual function table, rather than inline the function). Pointers to virtual member functions are quite a tricky subject in C++.

like image 1
Mats Petersson Avatar answered Oct 16 '22 10:10

Mats Petersson