2016-12-19 7 views
4

128ビットのxmmレジスタを2つの64ビットクワッドワードに分割する方法はありますか?XMM 128ビットレジスタを2つの64ビット整数レジスタに分割する方法は?

私はxmm1では非常に数が多いとr10、またはRAXRDXr9に高いクワッドワードと下位クワッドワードを取得したいです。

movlpdまたはmovhpdは、reg to memまたはその逆の場合にのみ機能します。

+1

いくつかの提案を得るためにgcc(そしてバージョンが '0')で' long long f(long long __attribute __(vector_size(16)))x){return x [1];} 'をコンパイルしてください... –

答えて

4

SSE2(x86-64のベースライン)には、XMMと整数レジスタ間で直接データを移動するための命令があります(メモリをバウンドせずに)。ベクトルの下位要素は簡単です:MOVD or MOVQ。より高い要素を抽出するには、必要な要素をベクトルの下位要素にシャッフルするだけです。

16ビット以外のサイズ(例:PEXTRQ)のSSE4.1も追加されました。 code-size以外はnot actually faster than a separate shuffle and movq on any existing CPUsですが、余分なtmpレジスタは必要ありません。

#SSE4.1 
movq rax, xmm0  # low qword 
pextrq rdx, xmm0, 1 # high qword 
# 128b result in rdx:rax, ready for use with div r64 for example. 
# (But watch out for #DE on overflow) 
# also ready for returning as a __int128_t in the SystemV x86-64 ABI 

#SSE2 
movq  r10, xmm0 
punpckhqdq xmm0, xmm0 # broadcast the high half of xmm0 to both halves 
movq  r9, xmm0 

これを行う最も効率的な方法は、PUNPCKHQDQです。 65nm Core2(Merom/Conroe)のように、64ビットより小さい要素サイズのための遅いシャッフルを持つ古いCPUでも高速です。詳細については、my horizontal sum answerを参照してください。 PUNPCKHQDQは即値オペランドを持たず、SSE2のみであるため、コードサイズはわずか4バイトです。

xmm0の元の値を保持するには、異なる宛先のpshufdを使用します。あるいは、ハイ・ロー・ハーフをイン・プレースなどに入れ替えることができます。


movlpdまたはmovhpd ...

今までにそれらを使用するにはポイントがありません。代わりにmovlps/movhpsを使用してください。なぜなら、それらがより短く、CPUがfloatとdoubleを気にしないからです。

movhlps xmm1, xmm0を使用すると、xmm0の上位半分を別のレジスタに抽出できますが、FPシャッフルと整数ベクトル演算を混在させると、一部のCPU(特にIntel Nehalem)でバイパス遅延が発生します。また、xmm1への依存性がレイテンシのボトルネックを引き起こすことに注意してください。

これは一般的にpshufdを好んでいます。しかし、movhlpsが高速で整数ドメインで実行され、pshufdが遅いCore2のような特定のCPUをチューニングする場合は、movhlpsを使用できます。

関連する問題