1. ホーム
  2. gcc

[解決済み] なぜGCCはa*a*a*a*aを(a*a*a)*(a*a*a)に最適化しないのでしょうか?

2022-03-16 20:35:30

質問

科学的なアプリケーションで数値の最適化を行っています。一つ気づいたことは、GCCは以下の呼び出しを最適化することです。 pow(a,2) にコンパイルすることで a*a が、呼び出しの pow(a,6) は最適化されておらず、実際にはライブラリ関数 pow このため、パフォーマンスが大幅に低下します。(これに対して インテル® C++ コンパイラー は、実行可能な icc のライブラリ呼び出しが不要になります。 pow(a,6) .)

気になるのは、置き換えを行った際に pow(a,6)a*a*a*a*a*a GCC 4.5.1、オプション " を使用しています。 -O3 -lm -funroll-loops -msse4 を使用する場合、5 mulsd という命令があります。

movapd  %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13

と書く一方で (a*a*a)*(a*a*a) を生成します。

movapd  %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm13, %xmm13

で、乗算命令数を3個に減らすことができます。 icc も同様の動作をします。

なぜコンパイラはこの最適化のトリックを認識しないのでしょうか?

解決方法は?

なぜなら 浮動小数点演算は連想演算ではない . 浮動小数点演算のオペランドをグループ化する方法は、答えの数値精度に影響を及ぼします。

そのため、ほとんどのコンパイラーは、答えが変わらないことが確実な場合や、数値の精度を気にしないと言われない限り、浮動小数点演算の並べ替えには非常に保守的になっています。 例えば その -fassociative-math オプション は、gcc が浮動小数点演算を再割り当てできるようにするもので、あるいは -ffast-math オプションを使用すると、精度と速度のトレードオフをより積極的に行うことができます。