2016-12-05 34 views
4

SIMD演算を使用して、最小値/最大値をバイト配列に配置したいと考えています。今まで私は配列を通って_m128i変数に最小値/最大値を格納することができましたが、それは私が探している値が他のものと混在していることを意味します。SIMD:_m128iから最小/最大値を見つける

整数の場合はherehere、浮動小数点の場合はthis pageですが、_mm_shuffle *の仕組みはわかりません。だから私の質問は:

  1. 最小/最大バイト(または符号なしバイト)の値を_m128i変数から抽出するには、どのような操作が必要ですか?
  2. _mm_shuffle *はどのように機能しますか?オンラインで「最小限の」ドキュメンテーションを見ると、私はそれを理解できません。私はそれが_MM_SHUFFLE macroに関連していることを知っていますが、私は例を得ていません。ここ
+0

それは、そこに文書化ほとんどの組み込み関数のhttps://software.intel.com/sites/landingpage/IntrinsicsGuide/を試すことができます場合は、それが正確に –

答えて

4

uint8_t水平maxの例である:

#include "tmmintrin.h" // requires SSSE3 

__m128i _mm_hmax_epu8(const __m128i v) 
{ 
    __m128i vmax = v; 

    vmax = _mm_max_epu8(vmax, _mm_alignr_epi8(vmax, vmax, 1)); 
    vmax = _mm_max_epu8(vmax, _mm_alignr_epi8(vmax, vmax, 2)); 
    vmax = _mm_max_epu8(vmax, _mm_alignr_epi8(vmax, vmax, 4)); 
    vmax = _mm_max_epu8(vmax, _mm_alignr_epi8(vmax, vmax, 8)); 

    return vmax; 
} 

最大値は、すべての要素に返されます。値がスカラーとして必要な場合は、_mm_extract_epi8を使用します。

minとsigned min/maxに対してこれをどのように適応させるべきかは、かなり明白です。また

+1

おかげで多くのことを何の詳細な擬似コード表現があります、私はそれをできるだけ早くテストします! – FiReTiTi

+2

最後の2つのシャッフルについては、PSHUFD( '_mm_shuffle_epi32')を使用していくつかのMOVDQA命令を保存することができます。これは粒度> = 4です。結果ブロードキャストが必要ない場合、逆順に進み、下半分のラインナップに半減します。そうすれば、PSHUFLWをワードシャッフルに使うことができます。これは、それがムーブ+シャッフルであるという事実を再び利用します。 (PALIGNRはその場所をインプレースで更新するので、AVXなしでコンパイラは 'vmax'をコピーしなければならないので、PMAXUBの入力として元のままです)。 –

+0

@PeterCordes:はい、シャッフルに良い点があります。これはパフォーマンスに重大ではないと想定していました。最小/最大の削減の最終段階にのみ必要ですが、そうであれば、推奨するように修正する価値があります。 –

1

、言葉に変換して、私の迅速なカウントだけphminposuw(テストしていません)

int hminu8(__m128i x) 
{ 
    __m128i l = _mm_unpacklo_epi8(x, _mm_setzero_si128()); 
    __m128i h = _mm_unpackhi_epi8(x, _mm_setzero_si128()); 
    l = _mm_minpos_epu16(l); 
    h = _mm_minpos_epu16(h); 
    return _mm_extract_epi16(_mm_min_epu16(l, h), 0); 
} 

を使用し、待ち時間はビット分/シャッフルカスケードよりも悪いが、スループットは少し良いです。 phminposuwのリンクされた答えはおそらくよりよいです。符号なしバイトのために適合さ

uint8_t hminu8(__m128i x) 
{ 
    x = _mm_min_epu8(x, _mm_srli_epi16(x, 8)); 
    x = _mm_minpos_epu16(x); 
    return _mm_cvtsi128_si32(x); 
} 

あなたはあまりにも最高のためにそれを使用することができます(ただし、テストされていない)が、オーバーヘッドのビットは:入力と結果を補完します。

+3

これにはIntel Pentryn以降のSSE 4.1が必要です。 CPUIDを使用し、SSE41ビット・フラグをテストすることにより、実行時にサポートをチェックできます。 –

1

ここには256ビット版があります。それは完全にテストされていないので、私は短いフィードバックを感謝します。

#include "immintrin.h" 

uint8_t max_u8 (const __m256i v) 
{ 
    __m256i gm = v; 
    gm = _mm256_max_epu8 (gm, _mm256_slli_si256 (gm, 1)); 
    gm = _mm256_max_epu8 (gm, _mm256_slli_si256 (gm, 2)); 
    gm = _mm256_max_epu8 (gm, _mm256_slli_si256 (gm, 4)); 
    gm = _mm256_max_epu8 (gm, _mm256_slli_si256 (gm, 8)); 
    gm = _mm256_max_epu8 (gm, _mm256_slli_si256 (gm, 16)); 
    return _mm256_extract_epi8 (gm, 31); 
} 
関連する問題