論理的なSSEの内因性の違いは何ですか?
-
25-09-2019 - |
質問
さまざまなタイプの論理SSE内因性に違いはありますか?たとえば、服用または操作の場合、_mm_or_ps、_mm_or_pd、_mm_or_si128の3つの内因性があります。 ビットワイズ または彼らの手術の。私の質問:
一方または別の本質的な(適切なタイプのキャストを使用)使用することに違いはありますか?特定の状況での長い実行のような隠れたコストはありませんか?
これらの内因性は、3つの異なるX86命令(POR、ORPS、ORPD)にマッピングします。 Intelが同じことをするいくつかの指示のために貴重なオプコードスペースを無駄にしている理由はありますか?
解決
3つすべてが事実上同じ、つまり128ビットワイズ操作だと思います。異なる形式が存在する理由はおそらく歴史的ですが、私は確信していません。そうだと思います 可能 フローティングポイントバージョンに追加の動作がある可能性があります。たとえば、ナンがある場合ですが、これは純粋な推測です。通常の入力の場合、指示は交換可能であるように見えます。
#include <stdio.h>
#include <emmintrin.h>
#include <pmmintrin.h>
#include <xmmintrin.h>
int main(void)
{
__m128i a = _mm_set1_epi32(1);
__m128i b = _mm_set1_epi32(2);
__m128i c = _mm_or_si128(a, b);
__m128 x = _mm_set1_ps(1.25f);
__m128 y = _mm_set1_ps(1.5f);
__m128 z = _mm_or_ps(x, y);
printf("a = %vld, b = %vld, c = %vld\n", a, b, c);
printf("x = %vf, y = %vf, z = %vf\n", x, y, z);
c = (__m128i)_mm_or_ps((__m128)a, (__m128)b);
z = (__m128)_mm_or_si128((__m128i)x, (__m128i)y);
printf("a = %vld, b = %vld, c = %vld\n", a, b, c);
printf("x = %vf, y = %vf, z = %vf\n", x, y, z);
return 0;
}
$ gcc -Wall -msse3 por.c -o por
$ ./por
a = 1 1 1 1, b = 2 2 2 2, c = 3 3 3 3
x = 1.250000 1.250000 1.250000 1.250000, y = 1.500000 1.500000 1.500000 1.500000, z = 1.750000 1.750000 1.750000 1.750000
a = 1 1 1 1, b = 2 2 2 2, c = 3 3 3 3
x = 1.250000 1.250000 1.250000 1.250000, y = 1.500000 1.500000 1.500000 1.500000, z = 1.750000 1.750000 1.750000 1.750000
他のヒント
- 一方または別の本質的な(適切なタイプのキャストを使用)使用することに違いはありますか?特定の状況での長い実行のような隠れたコストはありませんか?
はい、1つを選択するパフォーマンスの理由がある場合があります。
1: 整数実行ユニットの出力をFP実行ユニットの入力にルーティングする必要がある場合、またはその逆の場合、追加のサイクル(転送遅延)が追加される場合があります。 128Bのデータを多くの可能な宛先のいずれかに移動するには多くのワイヤが必要なため、CPU設計者は、すべてのFP出力からすべてのFP入力への直接パスのみを持ち、すべての可能な入力ではなくトレードオフを行う必要があります。
見る この答え, 、 また Agner Fogのマイクロアーキテクチャドキュメント バイパスのように。 Agnerのドキュメントで「Nehalemのデータバイパス遅延」を検索します。いくつかの良い実用的な例と議論があります。彼は分析したすべてのマイクロアーチのセクションを持っています。
ただし、異なるドメインまたは異なるタイプのレジスタ間のデータを渡すデータの遅延は、ネハレムよりもサンディブリッジとアイビーブリッジの方が小さく、しばしばゼロです。 -Agner FogのMicro Arch Doc
レイテンシがコードの重要なパスにないかどうかは関係ないことを忘れないでください。使用 pshufd
それ以外の movaps + shufps
UOPスループットがあなたの重要なパスのレイテンシではなく、ボトルネックである場合、勝利になる可能性があります。
2: ...ps
バージョンは、他の2つよりも1バイトのコードを1つ少なくします。これにより、以下の指示が異なる方法で整列します。これは、デコーダーおよび/またはUOPキャッシュラインで重要です。
3: 最近のIntel CPUは、PORT5でFPバージョンのみを実行できます。
Merom(Core2)とPenryn:
orps
p0/p1/p5で実行できますが、整数ドメインのみです。おそらく、3つのバージョンすべてがまったく同じUOPにデコードされました。したがって、クロスドメイン転送の遅延が発生します。 (AMD CPUもこれを行います:FPビットワイズ命令はIVECドメインで実行されます。)Nehalem / Sandybridge / IVB / Haswell / Broadwell:
por
p0/p1/p5で実行できますがorps
port5でのみ実行できます。 P5はシャッフルでも必要ですが、FMA、FP ADD、およびFP MULユニットはポート0/1にあります。Skylake:
por
とorps
どちらにも3サイクルあたりのスループットがあります. 。転送遅延に関する情報はまだ利用できません。
SNB/IVB(AVXではなくAVX2)では、P5のみが256Bの論理OPSを処理する必要があることに注意してください。 vpor ymm, ymm
AVX2が必要です。ネハレムがこれを行ったので、これはおそらく変化の理由ではなかった。
賢明に選択する方法:
PORT5の論理OPスループットがボトルネックになる可能性がある場合は、FPデータでも整数バージョンを使用します。これは、整数シャッフルまたはその他のデータモーブメント手順を使用する場合に特に当てはまります。
AMD CPUは常に整数ドメインを論理に使用するため、複数の整数ドメインがある場合は、ドメイン間のラウンドトリップを最小限に抑えるために一度にそれらをすべて実行します。 DEPチェーンがコードのボトルネックではない場合でも、より短いレイテンシは、再注文バッファーから物事をより速く片付けます。
FP ADDとMULの指示の間のFPベクターで少し設定/クリア/フリップしたい場合は、 ...ps
単一および二重FPは存在するすべてのCPUで同じドメインであるため、二重精度データでも論理的なものであり、 ...ps
バージョンは1バイト短いです。
使用するには実用的 /人間の要因があります ...pd
ただし、バージョンは、1バイトのコードを保存することが多いことがよくあります。他の人間によるコードの読みやすさが要因です。彼らは、実際に2倍になったときに、なぜあなたがあなたのデータをシングルとして扱っているのか疑問に思うでしょう。特にC/C ++の内因性を使用して、コードにキャストに散らばっています __mm256
と __mm256d
それだけの価値はありません。 INSNアライメントのレベルでチューニングする場合は、本質的ではなく、ASMを直接書き込みます! (1バイトの命令を長くすると、UOPキャッシュラインの密度やデコーダーのために物事をより適切に揃える可能性があります。)
整数データには、整数バージョンを使用します。 1つの命令バイトを保存することは、バイパス遅延の価値はありません。整数コードは、PORT5をシャッフルで完全に占有し続けることがよくあります。 Haswellの場合、SNB / IVBのP1 / P5の代わりに、多くのシャッフル /インサート /エクステルクロック /パック /アンパック命令がP5のみになりました。
- これらの内因性は、3つの異なるx86命令にマッピングします(
por
,orps
,orpd
)。 Intelが同じことをするいくつかの指示のために貴重なオプコードスペースを無駄にしている理由はありますか?
これらの命令セットの歴史を見ると、ここでどのようになったかを見ることができます。
por (MMX): 0F EB /r
orps (SSE): 0F 56 /r
orpd (SSE2): 66 0F 56 /r
por (SSE2): 66 0F EB /r
MMXはSSEの前に存在していたので、SSEのオプコードのように見えます(...ps
)指示は同じものから選ばれました 0F xx
スペース。次に、SSE2の場合、 ...pd
バージョンが追加されました 66
オペランドサイズのプレフィックスへ ...ps
opcode、および整数バージョンが追加されました 66
MMXバージョンのプレフィックス。
彼ら できる 除外した orpd
および/または por
, 、しかし、彼らはしませんでした。おそらく彼らは、将来のCPU設計には異なるドメイン間のより長い転送パスがあるかもしれないと考えていたので、データに一致する命令を使用することがより大きな取引になるでしょう。別のオペコードがありますが、AMDと初期のインテルは、それらをすべてINTベクトルと同じように扱いました。
IntelおよびAMDの最適化ガイドラインによると、OPタイプとデータ型を混合すると、CPUが特定のデータ型のレジスタの64ビットの半分を内部的にタグ付けすると、パフォーマンスヒットが生成されます。これは、命令がデコードされ、UOPSがスケジュールされるため、パイプライニングにほとんど影響を与えるようです。機能的には同じ結果が生成されます。整数データ型の新しいバージョンのエンコードが大きく、コードセグメントでより多くのスペースを占有します。したがって、コードサイズが問題の場合、エンコードが小さいため、古いOPSを使用します。