7

SSE3 では、PALIGNR 命令は次のことを実行します。

PALIGNR は、デスティネーション オペランド (第 1 オペランド) とソース オペランド (第 2 オペランド) を中間コンポジットに連結し、バイト粒度でコンポジットを定数即値分だけ右にシフトし、右揃えの結果をデスティネーションに抽出します。

私は現在、SSE4 コードを移植して AVX2 命令を使用し、128 ビットではなく 256 ビット レジスタに取り組んでいる最中です。単純に、組み込み関数_mm256_alignr_epi8(VPALIGNR) が 256 ビット レジスタに対してのみ同じ操作を実行すると信じていました_mm_alignr_epi8。残念ながら、そうではありません。実際、_mm256_alignr_epi8256 ビット レジスタを 2 つの 128 ビット レジスタとして扱い、隣接する 2 つの 128 ビット レジスタに対して 2 つの「整列」操作を実行します。と同じ操作を効果的に実行します_mm_alignr_epi8が、一度に 2 つのレジスタに対して実行します。ここに最も明確に示されています: _mm256_alignr_epi8

現在、私の解決策は、次のよう_mm_alignr_epi8に、ymm (256 ビット) レジスタを 2 つの xmm (128 ビット) レジスタ (上位と下位) に分割して使用し続けることです。

__m128i xmm_ymm1_hi = _mm256_extractf128_si256(ymm1, 0);
__m128i xmm_ymm1_lo = _mm256_extractf128_si256(ymm1, 1);
__m128i xmm_ymm2_hi = _mm256_extractf128_si256(ymm2, 0);
__m128i xmm_ymm_aligned_lo = _mm_alignr_epi8(xmm_ymm1_lo, xmm_ymm1_hi, 1);
__m128i xmm_ymm_aligned_hi = _mm_alignr_epi8(xmm_ymm2_hi, xmm_ymm1_lo, 1);
__m256i xmm_ymm_aligned = _mm256_set_m128i(xmm_ymm_aligned_lo, xmm_ymm_aligned_hi);

これは機能しますが、もっと良い方法があるはずですよね? 同じ結果を得るために使用する必要がある、おそらくより「一般的な」AVX2命令はありますか?

4

3 に答える 3

5

何に使ってるpalignrの?データの不整合を処理するだけの場合は、代わりに不整合のロードを使用してください。これらは一般に、最新のIntel µアーキテクチャでは「十分に高速」です(コードサイズを大幅に節約できます)。

palignr他の理由で同様の動作が必要な場合は、アライメントされていないロードサポートを利用して、ブランチフリーの方法で実行できます。完全にロードストアに縛られていない限り、これはおそらく好ましいイディオムです。

static inline __m256i _mm256_alignr_epi8(const __m256i v0, const __m256i v1, const int n)
{
    // Do whatever your compiler needs to make this buffer 64-byte aligned.
    // You want to avoid the possibility of a page-boundary crossing load.
    char buffer[64];

    // Two aligned stores to fill the buffer.
    _mm256_store_si256((__m256i *)&buffer[0], v0);
    _mm256_store_si256((__m256i *)&buffer[32], v1);

    // Misaligned load to get the data we want.
    return _mm256_loadu_si256((__m256i *)&buffer[n]);
}

あなたがどれだけ正確に使用しているかについてのより多くの情報を提供することができればpalignr、私はおそらくもっと役立つことができます。

于 2011-12-26T16:29:21.757 に答える
3

このために私が思いついた唯一の解決策は次のとおりです。

static inline __m256i _mm256_alignr_epi8(const __m256i v0, const __m256i v1, const int n)
{
  if (n < 16)
  {
    __m128i v0h = _mm256_extractf128_si256(v0, 0);
    __m128i v0l = _mm256_extractf128_si256(v0, 1);
    __m128i v1h = _mm256_extractf128_si256(v1, 0);
    __m128i vouth = _mm_alignr_epi8(v0l, v0h, n);
    __m128i voutl = _mm_alignr_epi8(v1h, v0l, n);
    __m256i vout = _mm256_set_m128i(voutl, vouth);
    return vout;
  }
  else
  {
    __m128i v0h = _mm256_extractf128_si256(v0, 1);
    __m128i v0l = _mm256_extractf128_si256(v1, 0);
    __m128i v1h = _mm256_extractf128_si256(v1, 1);
    __m128i vouth = _mm_alignr_epi8(v0l, v0h, n - 16);
    __m128i voutl = _mm_alignr_epi8(v1h, v0l, n - 16);
    __m256i vout = _mm256_set_m128i(voutl, vouth);
    return vout;
  }
}

これは、16バイト以上のシフトも処理することを除けば、ソリューションとほとんど同じだと思います。

于 2011-12-15T09:53:44.123 に答える
3

「palignr」を 256 ビットに拡張するには、「vperm2i128」と「vpalignr」の 2 つの命令が必要です。

参照: https://software.intel.com/en-us/blogs/2015/01/13/programming-using-avx2-permutations

于 2015-08-10T19:25:02.410 に答える