6

This is more or less a request for clarification on Casting a function pointer to another type with example code

struct my_struct;
void my_callback_function(struct my_struct* arg);
void do_stuff(void (*cb)(void*));

static void my_callback_helper(void* pv)
{
    my_callback_function(pv);
}
int main()
{
    do_stuff(&my_callback_helper);
}

The answer says a "good" compiler should be able to optimize out the my_callback_helper() function but I found no compiler at https://gcc.godbolt.org that does it and the helper function gets always generated even if it's just a jump to my_callback_function() (-O3):

my_callback_helper:
        jmp     my_callback_function
main:
        subq    $8, %rsp
        movl    $my_callback_helper, %edi
        call    do_stuff
        xorl    %eax, %eax
        addq    $8, %rsp
        ret

So my question is: Is there anything in the standard that prevents compilers from eliminating the helper?

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • In my experience, compilers tend to do a poor job at inlining function pointer calls even if the function pointer's value can be determined at compile-time. You could try to toss in the `inline` keyword. As far as I know, there is nothing in the standard preventing the optimization. – Lundin Sep 27 '17 at 12:02

1 Answers1

3

There's nothing in the standard that directly prevents this optimization. But in practice, it's not always possible for compilers when they don't have a "full picture".

You have taken the address of my_callback_helper. So compiler can't easily optimize it out because it doesn't know what do_stuff does with it. In a separate module where do_stuff is defined, compiler doesn't know that it can simply use/call my_callback_function in place of its argument (my_callback_helper). In order to optimize out my_callback_helper completely, compiler has to know what do_stuff does as well. But do_stuff is an external function whose definition isn't available to compiler. So this sort of optimization may happen if you provide a definition for do_stuff and all its uses.

P.P
  • 117,907
  • 20
  • 175
  • 238
  • 1
    This should also be resloved by using link time optimization (-flto with GCC) during compile and "link" steps. – dbrank0 Sep 27 '17 at 12:23
  • I'm thinking perhaps it's forbidden because of the possibility pointer comparison. `do_stuff()` might be trying to compare the received pointer to `my_callback_function()`. With the optimization on, the comparison will say `my_callback_function == my_callback_helper`, and it might not be legal for two different objects to have the same address. If it is illegal, then it's a little unfortunate the jump can't be eliminated. Maybe it'd be better for fn-casts to be implementation-defined rather than undefined. – Petr Skocik Sep 27 '17 at 12:47