関連する話として、アロケータに、__attribute__((malloc))を付けましょうという話。
まず、
extern void * alloc_buffer( ); extern void free_buffer( int * ); int nanika( int *a ) { int x; int ret; int * buf = alloc_buffer( ); x = a[0]; buf[0] = 0; ret = x - a[0]; free_buffer( buf ); return ret; }
こういうコードを考える。さて、このコードの戻り値は?
0 … のように見える(x = a[0]; ret = x-a[0]; return 0;)けど、ひょっとすると、0ではないかもしれない。
なぜか?alloc_bufferの返してくる値が、int *aが指しているバッファと重なってるかもしれないから(何を言ってるかわからない人は、もう一度上の話を読み直そう。それでもわからない場合は、抗議のメールを出そう!そんなことされたら困る)。
上のをコンパイルすると、
nanika: pushl %ebp movl %esp, %ebp pushl %esi pushl %ebx movl 8(%ebp), %ebx call alloc_buffer movl (%ebx), %esi subl $12, %esp movl $0, (%eax) subl (%ebx), %esi ; 減算 pushl %eax call free_buffer leal -8(%ebp), %esp popl %ebx movl %esi, %eax popl %esi leave ret
減算してるのがわかると思う。最適化してくれない。
ところが…!このコードを、
int nanika2( int *a ) { int x; int ret; int * buf = malloc( 10 ); x = a[0]; buf[0] = 0; ret = x - a[0]; free( buf ); return ret; }
こんなふうに、malloc、freeを使うように修正すると、
nanika2: pushl %ebp movl %esp, %ebp subl $20, %esp pushl $10 call malloc movl $0, (%eax) movl %eax, (%esp) call free xorl %eax, %eax leave ret
アラ不思議!減算処理が消えてしまいました!xorl eax, eax!(GCC4.1だとうまくいかない?GCC3.2だとうまくいった。)
実は、GCC拡張のattributeに、'malloc'というのがあって、
GCC info より
`malloc'
The `malloc' attribute is used to tell the compiler that a function
may be treated as if any non-`NULL' pointer it returns cannot
alias any other pointer valid when the function returns. This
will often improve optimization. Standard functions with this
property include `malloc' and `calloc'. `realloc'-like functions
have this property as long as the old pointer is never referred to
(including comparing it to the new pointer) after the function
returns a non-`NULL' value.
適当訳: `malloc' attribute は 関数が返すNULL以外の戻りポインタが他の有効なポインタとエイリアスしないものと示すのに使います。
これは、たまに最適化を良くします。
(以下略)
まあ、なんかそんな。戻したポインタがエイリアスしませんよ。と。そういう話。
extern void * alloc_buffer( ) __attribute__((malloc)); extern void free_buffer( int * ); int nanika( int *a ) { int x; int ret; int * buf = alloc_buffer( ); x = a[0]; buf[0] = 0; ret = x - a[0]; free_buffer( buf ); return ret; }
こうすると、ほら不思議。
というわけで、自分でアロケータ書いた場合は、__attribute__((malloc))を付けましょう