14

最新の CPU は、ネイティブ サイズの 2 つのワード間で拡張乗算を実行し、低い結果と高い結果を別々のレジスタに格納できます。同様に、除算を実行する場合、不要な部分を破棄する代わりに、商と剰余を 2 つの異なるレジスタに格納します。

次の署名を取るある種の移植可能なgcc組み込みがありますか:

void extmul(size_t a, size_t b, size_t *lo, size_t *hi);

またはそのようなもの、および除算の場合:

void extdiv(size_t a, size_t b, size_t *q, size_t *r);

コードに #ifdef を挿入することで、インライン アセンブリと靴べらの移植性を自分で実行できることはわかっています。また、部分和を使用して乗算部分をエミュレートすることもできますが (これはかなり遅くなります)、読みやすさのために避けたいと思います。確かにこれを行うための組み込み関数が存在しますか?

4

2 に答える 2

21

バージョン 4.6 以降の gcc では、__int128. これは、ほとんどの 64 ビット ハードウェアで機能します。例えば

64x64 ビットの乗算の 128 ビットの結果を取得するには、次のようにします。

void extmul(size_t a, size_t b, size_t *lo, size_t *hi) {
    __int128 result = (__int128)a * (__int128)b;
    *lo = (size_t)result;
    *hi = result >> 64;
}

x86_64 では、gcc はこれをコンパイルするのに十分スマートです。

   0:   48 89 f8                mov    %rdi,%rax
   3:   49 89 d0                mov    %rdx,%r8
   6:   48 f7 e6                mul    %rsi
   9:   49 89 00                mov    %rax,(%r8)
   c:   48 89 11                mov    %rdx,(%rcx)
   f:   c3                      retq   

ネイティブの 128 ビット サポートなどは必要なく、インライン展開後はmul命令のみが残ります。

編集: 32 ビット アーキテクチャでは、これは同様に機能します。シフト幅を 32 に置き換える必要があります__int128_tuint64_t最適化は古い gcc でも機能します。

于 2012-11-02T00:59:16.310 に答える