5

x32 ABIは、特に x86_64 アーキテクチャ用に生成されたコードの 32 ビット ポインターを指定します。これは、x86_64 アーキテクチャ (64 ビット CPU レジスタを含む) の利点と、32 ビット ポインターの削減されたオーバーヘッドを組み合わせたものです。

<stdint.h>ヘッダーは typedef int_fast8_tint_fast16_tint_fast32_t、およびint_fast64_t(および対応する unsigned 型など) を定義します。uint_fast8_tそれぞれは次のとおりです。

少なくとも指定された幅を持つすべての整数型の中で、通常最も高速に動作する整数型

脚注付き:

指定されたタイプは、すべての目的で最速であるとは限りません。ある型を別の型よりも優先して選択する明確な根拠が実装にない場合、実装は単純に、符号と幅の要件を満たす整数型を選択します。

N1570 C11ドラフトより引用)

問題は、x32 ABI の有無にかかわらず、x86_64 アーキテクチャに対してどのよう[u]int_fast16_t[u]int_fast32_t型を定義する必要があるかということです。これらのタイプを指定する x32 ドキュメントはありますか? それらは 32 ビット x86 定義 (両方とも 32 ビット) と互換性があるべきですか、それとも x32 は 64 ビット CPU レジスタにアクセスできるため、x32 ABI の有無にかかわらず同じサイズである必要がありますか? (x32 ABI が使用されているかどうかに関係なく、x86_64 には 64 ビットのレジスタがあることに注意してください。)

__x86_64__これはテストプログラムです (gcc 固有のマクロに依存します):

#include <stdio.h>
#include <stdint.h>
#include <limits.h>

int main(void) {
#if defined __x86_64__ && SIZE_MAX == 0xFFFFFFFF
    puts("This is x86_64 with the x32 ABI");
#elif defined __x86_64__ && SIZE_MAX > 0xFFFFFFFF
    puts("This is x86_64 without the x32 ABI");
#else
    puts("This is not x86_64");
#endif
    printf("uint_fast8_t  is %2zu bits\n", CHAR_BIT * sizeof (uint_fast8_t));
    printf("uint_fast16_t is %2zu bits\n", CHAR_BIT * sizeof (uint_fast16_t));
    printf("uint_fast32_t is %2zu bits\n", CHAR_BIT * sizeof (uint_fast32_t));
    printf("uint_fast64_t is %2zu bits\n", CHAR_BIT * sizeof (uint_fast64_t));
}

でコンパイルするとgcc -m64、出力は次のようになります。

This is x86_64 without the x32 ABI
uint_fast8_t  is  8 bits
uint_fast16_t is 64 bits
uint_fast32_t is 64 bits
uint_fast64_t is 64 bits

でコンパイルするとgcc -mx32、出力は次のようになります。

This is x86_64 with the x32 ABI
uint_fast8_t  is  8 bits
uint_fast16_t is 32 bits
uint_fast32_t is 32 bits
uint_fast64_t is 64 bits

(最初の行とは別に、gcc -m3232 ビット x86 コードを生成する と出力を一致させます)。

これは glibc (<stdint.h>ヘッダーを定義する) のバグですか、それとも x32 ABI 要件に従っているのでしょうか? x32 ABI ドキュメントまたはx86_64 ABI ドキュメント[u]int_fastN_tのいずれにもタイプへの参照はありませんが、それを指定する別のものがある可能性があります。

64ビットのレジスタが利用可能であるため、fast16およびfast32タイプはx32またはx32で64ビットにする必要があると主張することができます。それは現在の動作よりも理にかなっていますか?

(x32 ABI についてのみ尋ねた元の質問を大幅に編集しました。この質問では、x32 の有無にかかわらず x86_64 について尋ねています。)

4

3 に答える 3

1

一般的に言えば、x86-64 CPU では、32 ビット整数型は 64 ビット整数型よりわずかに高速であると予想されます。メモリ使用量が少ないという理由もありますが、64 ビット命令では 32 ビット命令よりも余分なプレフィックス バイトが必要なためです。32 ビット除算命令は 64 ビット除算命令よりも大幅に高速ですが、それ以外の命令実行レイテンシは同じです。

64 ビット レジスタにロードする場合、通常は 32 ビットを拡張する必要はありません。この場合、CPU は自動的に値をゼロ拡張しますが、部分的なレジスタ ストールを回避するため、これは通常は利点にすぎません。レジスターの上部に何がロードされるかは、レジスター全体が変更されるという事実ほど重要ではありません。レジスタの上位部分の内容は、32 ビット型を保持するために使用される場合、通常、レジスタの下位 32 ビット部分でのみ機能する 32 ビット命令でのみ使用されるため、重要ではありません。

x32 ABI と x86-64 ABI を使用する場合の型のサイズの不一致はint_fast32_t、ポインターが 64 ビット幅であるという事実によっておそらく最も正当化されます。32 ビット整数がポインターに追加されるたびに、拡張する必要があるため、x86-64 ABI を使用する場合にこれが発生する可能性が高くなります。

考慮すべきもう 1 つの要因は、x32 ABI の要点は、より小さな型を使用してパフォーマンスを向上させることです。ポインターおよび関連する型が小さくなることでメリットが得られるアプリケーションは、小さくなることでメリットも得られるはずint_fast32_tです。

于 2016-05-01T00:06:49.037 に答える
-3

タフ。int_fast8_t だけ取りましょう。開発者が大量の 8 ビット符号付き整数を格納するために大きな配列を使用する場合、キャッシングのために int8_t が最も高速になります。int_fast8_t の大きな配列を使用することは、おそらく悪い考えであると断言します。

大規模なコードベースを使用し、int8_t と署名された char とプレーン char を int_fast8_t で署名されている場合は体系的に置き換える必要があります。次に、int_fast8_t のさまざまな typedef を使用してコードをベンチマークし、最速のものを測定します。

未定義の動作が変更されることに注意してください。たとえば、255 を割り当てると、型が int8_t の場合は -1 になり、それ以外の場合は 255 になります。

于 2016-04-30T23:18:29.747 に答える