3

私は最近、int _mm_extract_epi8 (__m128i src, const int ndx)「インデックスによって選択されたパックされた整数配列要素から整数バイトを抽出する」という参照によると、SSE組み込みを使用しています。これはまさに私が欲しいものです。

ただし、文字列データと明示的な長さのパック比較を実行し、インデックスを生成する_mm_cmpestrion aを介してインデックスを決定します。_m128iこのインデックスの範囲は 0..16 で、0..15 は有効なインデックスを表し、16 はインデックスが見つからなかったことを意味します。インデックス位置で整数を抽出するために、次のことを考えました。

const int index = _mm_cmpestri(...);
if (index >= 0 && index < 16) {
  int intAtIndex = _mm_extract_epi8(..., index);
}

これにより、gcc (-O0) コンパイラ エラーが残ります。

エラー: セレクターは 0..15 の範囲の整数定数でなければなりません

この問題を回避する厄介な方法はswitch、インデックス_mm_extract_epi8に を設定し、範囲 0..15 の各インデックスに対して呼び出しを行うことです。私の質問は、私が見ていないより良い/より良い方法があるかどうかです。

更新: -O3 最適化では、コンパイル エラーは発生しません。それでも -O0 を使用します。

4

1 に答える 1

3

質問を要約して閉じるだけです。

[0..15] のインデックス i で_m128i sse、コンパイル時に i をリテラルに縮小できないバイトを抽出する 3 つのオプションについて説明しました。

1) スイッチ & _mm_extract_epi8:switchオーバー i と、[0..15] 内の各 i のケースを持ち、_mm_extract_epi8(sse,i);を実行します。i now はコンパイル時のリテラルであるため、動作します。

2) ユニオンハック: を持ってunion SSE128i { __m128i sse; char[16] array; }、それを として初期化しSSE128i sse = { _mm_loadu_si128(...) }、インデックス i のバイトに でアクセスしますsse.array[i]

3) i 番目の要素を位置 0 にシャッフルし、 : i 番目の要素を位置 0にシャッフルするために_mm_extract_epi8使用します。_mm_shuffle_epi8(sse,_mm_set1_epi8(i))で抽出し_mm_extract_epi8(sse,0)ます。

評価: Intel Sandy Bridge と AMD Bulldozer アーキテクチャで 3 つのオプションのベンチマークを行いました。切り替えオプションはわずかな差で勝ちました。誰かが興味を持っている場合は、より詳細な数値とベンチマークの設定を投稿できます。

更新: 評価 ベンチマークのセットアップ: 1GB ファイルの各バイトを解析します。特定の特殊なバイトについては、カウンターを増やします。_mm_cmpistri特殊バイトのインデックスを検索するために使用します。次に、前述の 3 つの方法のいずれかを使用してバイトを「抽出」し、カウンターがインクリメントされるケースの区別を行います。コードは、GCC 4.6 with を使用してコンパイルされました-std=c++0x -O3 -march=native

各方法について、ベンチマークは Sandy Bridge マシンで 25 回実行されました。結果 (秒単位の実行時間の平均および標準偏差):

切り替えて抽出: 平均: 1071.45 標準偏差: 2.72006

ユニオンハック: 平均: 1078.61 標準偏差: 2.87131

位置 0 からサッフルして抽出: 平均: 1079.32 標準偏差: 2.69808

違いはごくわずかです。生成された asm を見る機会はまだありません。でも、違いを見てみるのも面白いかもしれません。現時点では、非公開のソースが含まれているため、ベンチマークの完全なコードを公開することはできません。時間があれば、これらを抽出してソースを投稿します。

于 2012-10-26T09:24:03.220 に答える