Jump to content
  • Advertisement
Sign in to follow this  
Ro_Akira

C++ function pointer optimization

This topic is 4486 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Is there any chance of function calls via a pointer will be inlined and optimised away? Hypothetically speaking? I tried this simple contrived example in MSVC++ 2005 EE, Release, inlining Any Suitable, Link Time Code Generation (compiler+linker). The inline depth should be the default 254, but I manually set in anyway:
#pragma inline_depth(254)

inline int SimpleFunction ()
{
    return 1200;
}

typedef int (*SimpleFunctionPointerType) ();

// const there should make the function pointer const, I believe
SimpleFunctionPointerType const SimpleFunctionGlobalPointer (&SimpleFunction);

int main ()
{
    int k = 0;

    // const here should make the function pointer const, I believe
        SimpleFunctionPointerType const SimpleFunctionLocalPointer (&SimpleFunction);
        k += SimpleFunctionLocalPointer ();
004012AE  call        SimpleFunction (401250h)
004012B3  add         eax,edi
004012B5  add         esi,eax
        k += SimpleFunctionGlobalPointer ();
004012B7  call        dword ptr ds:[4021C8h]

    cout << k;
}

I'm trying to make things real simple here for the compiler. const function pointers to a locally declared function. It's interesting that the LocalPointer gets resolved to a regular function call, but then the compiler doesn't make the next step of inlining that (simple) function call. The call itself resolves to a mov eax,1200 ret :S Presumably there's greater difficulty involved in inlining the GlobalPointer, because the compiler has more trouble in general, determining if the pointer is safe/const?

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by Ro_Akira
Is there any chance of function calls via a pointer will be inlined and optimised away? Hypothetically speaking?


Hélas, no. I guess it's compiler dependent (I'm not brave enough to search the exact behavior in the Holy One). It's even the contrary: most of the time, you can force the compiler to not inline a function call by using a function pointer. For example, consider this code:


int function(int param)
{
return param+1;
}

int main(int argc, char* argv[])
{
int i;

i = function(100);

i = (true ? function : NULL) (i);

std::cout << "i = " << i << std::endl;

return 0;
}



The code resolves to:


int function(int param)
{
return param+1;
// 00401000 mov eax,dword ptr [esp+4]
// 00401004 inc eax
}
// 00401005 ret

// ----------------------

int main(int argc, char* argv[])
{
// 004018D0 push esi
int i;

i = function(100);

i = (true ? function : NULL) (i);
// 004018D1 push 65h // this is i = function(100);
// 004018D3 call function (401000h) // function is called, due to the function pointer
// 004018D8 add esp,4
// ...



As you see, even if the compiler knows that "function" will be called (true is always true, so there's only one code path), it still consider it as a pointer to function - while he correctly inlined function(100).

HTH,

Share this post


Link to post
Share on other sites
Quote:
Original post by Ro_Akira
Is there any chance of function calls via a pointer will be inlined and optimised away? Hypothetically speaking?

Yes. GCC 3.3.1 fully inlines every example given in this thread.

Σnigma

Share this post


Link to post
Share on other sites
Quote:
Original post by Ro_Akira
Is there any chance of function calls via a pointer will be inlined and optimised away? Hypothetically speaking?


Taking the address of a function makes it unsuitable for inlining. The compiler should not be inlining the call.

Quote:
// const here should make the function pointer const, I believe
SimpleFunctionPointerType const SimpleFunctionLocalPointer (&SimpleFunction);


There is no difference between const Foo and Foo const. There is a difference, however, between const Foo*, Foo const* on one hand, and Foo* const on the other.

Quote:
Presumably there's greater difficulty involved in inlining the GlobalPointer, because the compiler has more trouble in general, determining if the pointer is safe/const?


Not just more difficulty, it's impossible. For all the compiler knows, you could link against a DLL that modifies that global variable.

Share this post


Link to post
Share on other sites
Quote:
Original post by Fruny
Taking the address of a function makes it unsuitable for inlining. The compiler should not be inlining the call.

Since the observable behaviour is identical whether the function call is inlined or called through a function pointer a C++ compiler is perfectly within its rights to inline a call written using a function pointer under the "as-if" rule:
Quote:
C++ Standard, Final Draft, Section 1.8, Paragraph 1
The semantic descriptions in this International Standard define a parameterized nondeterministic abstract machine. This International Standard places no requirement on the structure of conforming implementations. In particular, they need not copy or emulate the structure of the abstract machine. Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below.3)

3) This provision is sometimes called the "as-if" rule, because an implementation is free to disregard any requirement of the Standard as long as the result is as if the requirement had been obeyed, as far as can be determined from the observable behavior of the program.


Quote:
Original post by Fruny
Not just more difficulty, it's impossible. For all the compiler knows, you could link against a DLL that modifies that global variable.

The function pointer was declared const. Therefore any attempt to modify it is undefined behaviour, thus allowing the compiler to inline the function call.

Σnigma

Share this post


Link to post
Share on other sites
Quote:
Is there any chance of function calls via a pointer will be inlined and optimised away? Hypothetically speaking?

Quote:
Hélas, no....

Quote:
Yes...

Unless Hélas has a meaning of 'Opposite of ' or similar, these two arguments appear to be in conflict.

Quote:
There is no difference between const Foo and Foo const. There is a difference, however, between const Foo*, Foo const* on one hand, and Foo* const on the other.

Understood, and I thought what I gave would be an example of the later (Foo* const). Anyway, I changed the typedef to
typedef int (*const SimpleFunctionPointerType) ();

and it made no difference - to the compiler's output at least.

Quote:
The function pointer was declared const. Therefore any attempt to modify it is undefined behaviour, thus allowing the compiler to inline the function call.

You see, this is what I'm getting at. If the compiler has a const pointer, to a function that it knows won't be coming from a DLL or some such, then it should be able to resolve it to a non function call, and thus inline. This is my thinking anyway. How common const pointers are, is another thing. Although references should provide the same opportunities as a const pointers should they not?

Check out the resolving it does to the LocalPointer above. Do my eyes deceive me, or is that a simple function call, which should in turn be inlined? Can anyone explain the behaviour?

I'll see if I can check out gcc...

Share this post


Link to post
Share on other sites
Fruny just got beaten at the standards game; I am in awe.

Anyhow, OP, you probably shouldn't even worry about it. The odds that will be the bottleneck of your program are VERY small.

Share this post


Link to post
Share on other sites
Quote:
Anyhow, OP, you probably shouldn't even worry about it. The odds that will be the bottleneck of your program are VERY small.

Most likely. But it's just interesting to know sometimes :)

Share this post


Link to post
Share on other sites
Quote:

I'll see if I can check out gcc...


GCC converts both calls via function pointer to direct calls, even with optimisation disabled. With -O3, both calls to the function compile down to a single instruction:
mov eax, 2400


EDIT: Now I see this was posted earlier, by Enigma:

Quote:
GCC 3.3.1 fully inlines every example given in this thread.

Share this post


Link to post
Share on other sites
Even in debug you say? GCC kicks far more ass than I suspected :o

The example that Emmanuel Deloget provided:

i = (true ? function : NULL) (i);
// 004018D1 push 65h // this is i = function(100);
// 004018D3 call function (401000h) // function is called, due to the function pointer
// 004018D8 add esp,4





I get the same result as Emmanuel with VC++ 2005 EE Release. If I change it to a comparable if-else statement though, the compiler sees it for what it is. Is the conditional operator handled differently by the compiler? A question for another thread I guess.
Edit: Enigma said all mentioned in the thread to his post were inlined - I presume he's including this too! I thought VC++ 2005 was pretty good until today, what with it's Link Time Program Generation and all.

=== C++ - Virtual Functions ===
You'll notice that I mentioned C++ in this thread's title, but mostly I've been talking just about function pointers. The whole reason I got into this line of thought is with C++ encounters like this:

Derived d;

int Derived::VirtualFunction () const
{
return simple_expression;
}

void Function (const Base& b)
{
cout << b->VirtualFunction () << endl;
}

int main ()
{
Derived d;

Function (d);

return 0;
}


When I was finding that even simple
base_pointer_to_base_object->VirtualFunction ()

calls were not being inlined, I simplified the question to functions being called by pointers in general.

Is there any chance for the compiler to inline the above call to VirtualFunction within Function, as called?

[Edited by - Ro_Akira on June 6, 2006 10:40:13 AM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!