後続の2つの呼び出しに同じ引数がある場合、副作用のある関数は1回だけ呼び出す必要があることをgccに伝える方法はありますか?次の動作が必要です。
foo(6);//run this function
foo(6);//optimize this away
foo(6);//optimize this away
foo(5);//run this function
foo(6);//run this function again
foo
作業を行う前にグローバル変数をチェックすることはできますが、それは最適ではありません。
void inline foo(int i){
static int last_i=i+1;
if(last_i != i){
last_i==i;
//do_work...
}
}
以来foo
、インライン関数があるコンパイラがのinvokations見ていくことができるはずですfoo()
、それはそれを実行する必要がないことを参照してください。問題は、コンパイラーがグローバル変数に対してそのように最適化できないことです。コンパイラーにそれが安全であることを知らせる方法はありますか?
したがって、最後に使用した引数をチェックすることを躊躇した理由は、関数呼び出しが非常にタイトな内部ループ内にあったため、特に分岐予測のある(または非常に貧弱な)プラットフォームでは、余分な比較と分岐命令が煩わしいためです。 。
私はそれを試したときにgccが何をするかを見ることにしました。次のコードを使用しました。
#include <stdio.h>
int check;
void myfun(int num){
printf("changing to %d\n",num);
}
static inline __attribute__((always_inline)) void idem(int num){
if(num!=check){
myfun(num);
check=num;
}
}
int main(){
idem(5);
idem(5);
idem(4);
idem(4);
return 0;
}
これgcc -O2 main.c
は、x86(私の最終ターゲットではない)で()を次のようにコンパイルします:
0000000000400440 <main>:
400440: 48 83 ec 08 sub $0x8,%rsp
400444: 83 3d e5 0b 20 00 05 cmpl $0x5,0x200be5(%rip) # 601030 <check>
40044b: 74 14 je 400461 <main+0x21>
40044d: bf 05 00 00 00 mov $0x5,%edi
400452: e8 09 01 00 00 callq 400560 <myfun>
400457: c7 05 cf 0b 20 00 05 movl $0x5,0x200bcf(%rip) # 601030 <check>
40045e: 00 00 00
400461: bf 04 00 00 00 mov $0x4,%edi
400466: e8 f5 00 00 00 callq 400560 <myfun>
40046b: c7 05 bb 0b 20 00 04 movl $0x4,0x200bbb(%rip) # 601030 <check>
400472: 00 00 00
400475: 31 c0 xor %eax,%eax
400477: 5a pop %rdx
400478: c3 retq
400479: 90 nop
40047a: 90 nop
40047b: 90 nop
ご覧のとおり、myfunは私が望むように2回しか呼び出されません。したがって、gccがこれを正しく行うことが可能であるように見えます。誰かがここでの最適化の制限についてチャイムを鳴らしたいのなら、私は非常に興味があります
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加