gcc 4.0 で lucille のコンパイル不都合

by syoyo

Tiger では開発ツールをインストールすると標準で gcc 4.0 のコンパイラがインストールされます。

で、gcc 4.0 で lucille をコンパイルしてみたのですが、最適化が有効になっていると、
コンパイルは通るのですが、結果の画像が真っ白、という結果となりました。

colinux に gcc 4.0 をコンパイルしてインストールして、同じように lucille をコンパイルしても
同じ結果となりました。

いくつか手探りでまずそうなコードをあたってみたところ、ひとつ原因がみつかりました。

flipcode に載っていた、逆平方根を求めるコードです。

 

float fastrsqrt(float number) {
        long i;
        float x2, y;
        const float threehalfs = 1.5f;

        x2 = (number) * 0.5f;
        y  = (number);
        i  = *(long *)&y;
        i  = 0x5f3759df - (i << 1);
        y  = *(float *)&i;
        y  = y * (threehalfs - (x2 * y * y));

        return y;
}

-O2 などの最適化オプションをつけると、なぜか間違った値が出力されてしまいます。
-Wall をつけると、コンパイル時に

warning: dereferencing type-punned pointer will break strict-aliasing rules

という警告を出すので(これがどういう意味なのかよく理解できていませんが、
無理やり違う型同士を変換すると出るみたい…)、
これが原因でしょうか。

まあもともと私も意味があまりわからないようなトリッキーなコードですので、
いつコンパイルが通らなくなってもおかしくはないコードではあります。

あまり高速化を求めてへんてこりんなコードを書くよりは、
安全で素直なコードを使ったほうがのちのち問題なさそうですね。

ほかにも lucille には gcc 4.0 ではうまく通らない(そもそも C 言語の仕様から外れているコード?)
コードがあるでしょうから、しばらくは gcc 4.0 用にコードの見直しです。

ちなみに、上記のコードは、union を使って以下のように対処すれば動きました。

float fastrsqrt(float number) {
        long i;
        float x2, y;
        const float threehalfs = 1.5f;
        union {
                long l;
                float f;
        } data32;
        x2 = (number) * 0.5f;
        y  = (number);
        data32.f = y;
        //i  = *(long *)&y;
        i = data32.l;
        i  = 0x5f3759df - (i << 1);
        data32.l = i;
        //y  = *(float *)&i;
        y = data32.f;
        y  = y * (threehalfs - (x2 * y * y));

        return y;
}
Advertisements