const attribute

やっぱり最適化で消えてしまうことがあるのか?
関数や手続きはその中で何やってるか分からんから,消さないと思ってい
た (代入して,後ろの方でその変数を使うからなおさらそう思っていた).
標準で用意されているものは容赦なく消すこともあるのかも.

入出力関数など関数呼び出しは副作用を期待している場合もあるので、「中で何やっているかわからないから消さない」というのは一般的には正しい。
で、まぁ、現に例の uipower_libm もコンパイル単位を分けると関数呼び出しが残る。

#include <math.h>

unsigned long uipower_libm(unsigned long b, unsigned long n)
{
    return pow(b, n);
}
#include <stdio.h>

#define REPEAT 100000000

unsigned long uipower_libm(unsigned long b, unsigned long n);

int main()
{
    int i;
    unsigned long m;

    for (i = 0; i < REPEAT; i++) {
        m = uipower_libm(3, 100);
    }

    return 0;
}
% gcc -Wall -W -O2 -pg -g -o pow pow.c main.c
% time ./pow
./pow  33.15s user 0.08s system 98% cpu 33.651 total
% gprof pow
(snip)
granularity: each sample hit covers 4 byte(s) for 0.08% of 12.61 seconds

  %   cumulative   self              self     total           
 time   seconds   seconds    calls  ms/call  ms/call  name    
 46.5       5.87     5.87 100000000     0.00     0.00  _uipower_libm [3]
 41.8      11.14     5.28                             _pow [4]
  6.3      11.93     0.79                             _moncount (2601)
  2.5      12.25     0.32                             mcount (27)
  2.1      12.52     0.27        1   270.00  6135.00  _main [1]
  0.5      12.59     0.07                             __dyld_func_lookup [5]
  0.1      12.60     0.01                             _vm_purgable_control [6]
  0.1      12.61     0.01                             _monreset (2605)
(snip)

gcc の場合、関数宣言に const attribute を付けてやると副作用がないことを宣言できたりする。
ちょと改造してみる。

% diff -u main.c{.orig,}
--- main.c.orig 2007-12-17 21:04:33.000000000 +0900
+++ main.c      2007-12-17 21:04:49.000000000 +0900
@@ -3,6 +3,7 @@
 
 #define REPEAT 100000000
 
+__attribute__((const))
 unsigned long uipower_libm(unsigned long b, unsigned long n);
 
 int main()
% gcc -Wall -W -O2 -pg -g -o pow pow.c main.c
% time ./pow
./pow  0.06s user 0.01s system 39% cpu 0.200 total
% gprof pow
(snip)
granularity: each sample hit covers 4 byte(s) for 33.33% of 0.03 seconds

  %   cumulative   self              self     total           
 time   seconds   seconds    calls  ms/call  ms/call  name    
100.0       0.03     0.03        1    30.00    30.00  _main [1]
(snip)

関数呼び出しが消えた。
まぁ、そういう訳で、あの例での uipower_libm はコンパイラが副作用無しと認識できてその戻り値も使っていないことが分かったから呼び出しを削除したわけ。