4

私は SSE の初心者で、組み込み関数を使用してコードのセクションを最適化しました。操作自体には満足しているのですが、結果の書き方をもっとうまくできないかと模索中です。結果は 3 つの_m128i変数になります。

私がやろうとしているのは、結果値から特定のバイトを連続しないメモリ位置に保存することです。私は現在これをやっています:

__m128i values0,values1,values2;

/*Do stuff and store the results in values0, values1, and values2*/

y[0]        = (BYTE)_mm_extract_epi16(values0,0);
cb[2]=cb[3] = (BYTE)_mm_extract_epi16(values0,2);
y[3]        = (BYTE)_mm_extract_epi16(values0,4);
cr[4]=cr[5] = (BYTE)_mm_extract_epi16(values0,6);

cb[0]=cb[1] = (BYTE)_mm_extract_epi16(values1,0);
y[1]        = (BYTE)_mm_extract_epi16(values1,2);
cr[2]=cr[3] = (BYTE)_mm_extract_epi16(values1,4);
y[4]        = (BYTE)_mm_extract_epi16(values1,6);

cr[0]=cr[1] = (BYTE)_mm_extract_epi16(values2,0);
y[2]        = (BYTE)_mm_extract_epi16(values2,2);
cb[4]=cb[5] = (BYTE)_mm_extract_epi16(values2,4);
y[5]        = (BYTE)_mm_extract_epi16(values2,6);

ここyで、、、cbおよびcrはバイト ( unsigned char) 配列です。私が定義できない理由から、これは私には間違っているようです。より良い方法について何か提案はありますか?

ありがとう!

4

4 に答える 4

8

基本的にはできません。SSE にはスキャッター ストアがなく、連続したデータ ストリームに対してベクトル化された作業を行うという考えに基づいて設計されています。実際、SIMD を作成する作業のほとんどは、連続してベクトル化できるようにデータを再配置することです。したがって、データ構造を再編成して、一度に 16 バイトを書き込めるようにするのが最善の方法です。コンポーネントをメモリにコミットする前に、SIMD ベクトル内のコンポーネントを並べ替えることができることを忘れないでください。

それができない場合、PEXTRWop (_mm_extract_epi16 組み込み) は、SSE レジスタからショートを取得して整数レジスタに格納する唯一の方法です。利用可能な他のアプローチは、アンパックおよびシャッフル ops (など) を使用してデータ_mm_shuffle_psをレジスタの下位ワードにローテーションし、その下位ワードを一度に 1 つずつメモリに格納することです。MOVSS_mm_store_ss()

おそらく、共用体を使用したり、SSE と汎用レジスターの間でデータを移動したりすると、ロード-ヒット-ストアストールと呼ばれる微妙な CPU 実装の詳細が原因で、パフォーマンスが非常に低下することがわかります。基本的に、レジスタ タイプ間でデータを直接移動する方法はありません。プロセッサは、最初に SSE データをメモリに書き込み、次にそれを再び GPR に読み込む必要があります。多くの場合、これは、ロード操作を停止し、ストアがクリアされるまで待ってから、それ以上の命令を実行する必要があることを意味します。

于 2010-10-19T20:29:39.783 に答える
2

特に SSE については知りませんが、ベクトル化されたユニットの全体的なポイントは、データが特定の配置とフォーマットに従っている場合、非常に高速に動作できることです。そのため、正しい形式と配置でデータを提供して抽出するのはあなた次第です。

于 2010-10-19T15:14:12.050 に答える
2

SSE には必要なスキャッター/ギャザー機能がありませんが、これはおそらく将来の SIMD アーキテクチャーで提供される予定です。

すでに提案されているように、ユニオンを使用できます。

typedef union
{
    __m128i v;
    uint8_t a8[16];
    uint16_t a16[8];
    uint32_t a32[4];
} U128;

この種の操作は、連続するデータ要素に対する単純な SIMD 操作と比較して非常に非効率的であるため、重要なループの外側でのみ発生することが理想的です。

于 2010-10-19T20:11:26.287 に答える
0

ユニオンを使用してバイトを抽出することができます。

union
{
    float value;
    unsigned char ch[8];
};

次に、必要に応じてバイトを割り当てます
。unsigned char ch[8] を匿名の構造体に置き換えますか? たぶん、ここ
からさらにいくつかのアイデアを得ることができます

于 2010-10-19T15:28:45.377 に答える