SSE内因性のない矛盾していないメモリロケーションに値を保存する方法は?
-
09-10-2019 - |
質問
私はSSEを非常に初めて使用しており、Intrinsicsを使用してコードのセクションを最適化しました。私は操作自体に満足していますが、結果を書くためのより良い方法を探しています。結果は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
)アレイ。これは、私が定義できない理由で私には間違っているようです。誰かがより良い方法のために何か提案がありますか?
ありがとう!
解決
基本的にはできません - SSEには散布ストアがありません。また、隣接するデータストリームでベクトル化された作業を行うというアイデアを中心に設計されています。本当に、何かを作ることに関与する作業のほとんどはsimd は データを再配置して、隣接してベクトル化できるようにします。したがって、最善のことは、データ構造を再配置して、一度に16バイトを書き込むことができるようにすることです。メモリにコミットする前に、SIMDベクトル内のコンポーネントを並べ替えることができることを忘れないでください。
それに失敗する、 PEXTRW
op(_mm_extract_epi16本質的)は、SSEレジスタからショートを引き出して整数レジスタに保存する唯一の方法です。あなたが利用できる他のアプローチは、開梱とシャッフルOPSを使用することです(_mm_shuffle_ps
など)データをレジスタの低い単語に回転させ、次に MOVSS
/_mm_store_ss()
その低い単語を一度に1つずつ保存する。
おそらく、組合を使用するか、SSEと汎用のレジスタとの間でデータを移動すると、微妙なCPU実装の詳細があるため、パフォーマンスが非常に低下することがわかります。 ロード-打つ-お店 ストール。基本的に、レジスタタイプ間でデータを移動する直接的な方法はありません。プロセッサは、まずSSEデータをメモリに書き込み、次にGPRに再度読み戻す必要があります。多くの場合、これは、負荷操作を停止し、さらに指示が実行されるまでストアがクリアされるまで待つ必要があることを意味します。
他のヒント
SSEについては特にわかりませんが、一般的に、ベクトル化ユニットの全体的なポイントは、データが特定のアライメントとフォーマットに従うと、非常に速く動作できることです。そのため、正しい形式とアラインメントでデータを提供および抽出するのはあなた次第です。
SSEには、必要な散布/収集機能はありませんが、これはおそらく将来のSIMDアーキテクチャに来ています。
すでに提案されているように、あなたは組合を使用することができます:例:
typedef union
{
__m128i v;
uint8_t a8[16];
uint16_t a16[8];
uint32_t a32[4];
} U128;
理想的には、この種の操作は、隣接するデータ要素のSIMD操作と比較して非常に非効率的であるため、重要なループの外でのみ発生します。
ユニオンを使用してバイトを抽出しようとすることができます。
union
{
float value;
unsigned char ch[8];
};
必要に応じてバイトを割り当てます
Union-Ideaで遊んで、Unsigned Char Ch [8]を匿名の構造体に置き換えるかもしれませんか?
多分あなたはもう少しアイデアを得ることができます ここ