ホーム>source

1つの __m256 を合計する方法を知っています単一の合計値を取得します。しかし、私は8つのベクトルのような 入力

<前>ウィズウィズ

出力

<前>ウィズウィズ

私の方法。もっと良い方法があるかどうか知りたい。

<前>ウィズウィズ 1: a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], ....., ....., 8: h[0], h[1], h[2], h[3], h[4], a[5], a[6], a[7]
あなたの答え
  • 解決した方法 # 1

    更新:8つのAVX単精度浮動小数点ベクトルの8つの水平合計の計算 (私は思う)同じ問題ですが、_mm256_permute2f128_psの1つをブレンドで置き換えて解決しました。そして、シャッフルuopsを置き換えるより多くのブレンドを使用した別の答え。代わりにそれらの1つを使用してください。


    ブレンドを使用できず、シャッフルでボトルネックになる元の回答

    2x _mm256_permute2f128_ps を使用できます  垂直 vaddps の低車線と高車線を並べる 。これは2x extractf128 の代わりです  / insertf128 。これは2つの128b vaddps xmm もオンにします  単一の256b vaddps ymm への命令 。

    ウィズウィズ  単一の vperm2f128 と同じくらい速い  または vextractf128  Intel CPU。ただし、AMDでは低速です(ブルドーザーファミリでは8 m-op、4cレイテンシ)。それでも、AMDのパフォーマンスを気にしても、回避する必要があるほど悪くはありません。 (そして、置換の1つは実際には vinsertf128 )。


    <前>ウィズウィズ

    これは期待どおりにコンパイルされます。 2番目の vinsertf128  実際に __m256 hsum8(__m256 a, __m256 b, __m256 c, __m256 d, __m256 e, __m256 f, __m256 g, __m256 h) { // a = [ A7 A6 A5 A4 | A3 A2 A1 A0 ] __m256 sumab = _mm256_hadd_ps(a, b); __m256 sumcd = _mm256_hadd_ps(c, d); __m256 sumef = _mm256_hadd_ps(e, f); __m256 sumgh = _mm256_hadd_ps(g, h); __m256 sumabcd = _mm256_hadd_ps(sumab, sumcd); // [ D7:4 ... A7:4 | D3:0 ... A3:0 ] __m256 sumefgh = _mm256_hadd_ps(sumef, sumgh); // [ H7:4 ... E7:4 | H3:0 ... E3:0 ] __m256 sum_hi = _mm256_permute2f128_ps(sumabcd, sumefgh, 0x31); // [ H7:4 ... E7:4 | D7:4 ... A7:4 ] __m256 sum_lo = _mm256_permute2f128_ps(sumabcd, sumefgh, 0x20); // [ H3:0 ... E3:0 | D3:0 ... A3:0 ] __m256 result = _mm256_add_ps(sum_hi, sum_lo); return result; } にコンパイルします 、それは permute2f128 と同じ方法で各入力の低レーンのみを使用しているため  します。 gcc 4.7以降はこの最適化を行いますが、それよりもはるかに新しいclangバージョン(v3.7)のみが行います。古いclangが気になる場合は、ソースレベルでこれを行ってください。

    ソース行での節約は、命令での節約よりも大きい。なぜなら、 vinsertf128  命令をゼロにコンパイルします。これは単なるキャストです。どのコンパイラーも vinsertf128 を発行してはならない   _mm256_extractf128_ps(sumabcd, 0); 以外のimm8 。 ( vextractf128  低車線を取得するには常に優れています)。プレーンジョブのVEXプレフィックスには長いベクトルをエンコードする余地がないため、将来の使用に備えて命令バイトを浪費するというIntelの素晴らしい仕事です。

    2つの 1  命令は並列に実行できるため、単一の vmovdqa xmm/m128, xmm を使用します  レイテンシではなく、ほとんどがスループット(およびコードサイズ)の向上です。

    最終的な vaddps xmm を完全に排除することで3サイクルを削っています 、しかし。


    ウィズウィズ  3 uops、5cレイテンシ、2cあたり1スループットです。 (Skylakeの6cレイテンシ)。これら3つのuopsのうちの2つがシャッフルポートで実行されます。私はそれが基本的に2倍の vaddps ymm をしていると思います   vinsertf128 のオペランドを生成する 。

    vhaddps をエミュレートできれば  (または、少なくとも使用できる水平方向の操作を取得します)単一の shufps / addps  または何か、私たちは先に出てくるでしょう。残念ながら、その方法はわかりません。 1つのシャッフルは2つのベクトルからのデータで1つの結果のみを生成できますが、垂直 haddps への両方の入力が必要です  両方のベクトルからのデータを取得します。

    水平合計を別の方法で行うことは有望に思えるとは思いません。通常、haddは適切な選択ではありません。一般的なHorizo​​ntal-sumのユースケースでは、出力の1つの要素しか考慮されないためです。ここではそうではありません:すべての shufps のすべての要素  結果が実際に使用されます。

    addps

  • 前へ java - JPAクエリ:サブクエリをグループ化条件に結合する
  • 次へ javascript - ユーザーエージェント(ブラウザー)がhttps経由で資格情報を要求しない