2017-09-27 10 views
6

を最適化する。これは、サンプルコードと Casting a function pointer to another typeヘルパー関数

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); 
} 

の明確化のため、多かれ少なかれ要求である答えは「良い」、コンパイラが にmy_callback_helper()機能を最適化することができるはずと言うが、私が見つかりました。それとヘルパー関数は、常にそれがjust a jump to my_callback_function()(-O3)だ場合でも生成されますんhttps://gcc.godbolt.org でコンパイラなかっなし:

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 

だから私の質問です:コンパイラがヘルパーを削除するのを防ぐ標準の中に何かがありますか?

+0

コンパイラは、関数ポインタの値をコンパイル時に決定できたとしても、関数ポインタ呼び出しをインライン展開するのに苦労する傾向があります。あなたは 'inline'キーワードで投げようとすることができます。私が知る限り、標準には最適化を妨げるものは何もありません。 – Lundin

答えて

3

この最適化を直接防止する標準は何もありません。しかし、実際には、コンパイラが「完全な画像」を持たないときは常にそうであるとは限りません。

my_callback_helperのアドレスを使用しました。だから、コンパイラは、do_stuffが何をしているのか分からないので、それを簡単に最適化することはできません。 do_stuffが定義されている別のモジュールでは、コンパイラは、その引数(my_callback_helper)の代わりに単にmy_callback_functionを使用して呼び出すことはできません。 my_callback_helperを完全に最適化するために、コンパイラはdo_stuffが何をしているかを知る必要があります。しかし、do_stuffは外部関数であり、その定義はコンパイラでは使用できません。したがって、この種の最適化は、do_stuffの定義とそのすべての用途を定義した場合に発生する可能性があります。

+1

これは、コンパイル時およびリンク時にリンク時間の最適化(-flto with GCC)を使用することによっても再現する必要があります。 – dbrank0

+0

ポインタの比較の可能性があるため、おそらく禁止されていると思っています。 'do_stuff()'は、受け取ったポインタを 'my_callback_function()'と比較しようとしているかもしれません。最適化をオンにすると、比較は 'my_callback_function == my_callback_helper'となり、2つの異なるオブジェクトが同じアドレスを持つことは合法ではないかもしれません。それが違法であれば、少し不幸なことですが、ジャンプを排除することはできません。おそらく、fn-castsが未定義ではなく実装定義である方が良いでしょう。 – PSkocik

関連する問題