如何將128位xmm
寄存器拆分爲兩個64位四字?如何將XMM 128位寄存器分成兩個64位整數寄存器?
我在xmm1
一個非常大的數字,並希望得到更高的四字r9
和較低的四字r10
,或RAX
和RDX
。
movlpd
或movhpd
只適用於reg到mem,反之亦然。
如何將128位xmm
寄存器拆分爲兩個64位四字?如何將XMM 128位寄存器分成兩個64位整數寄存器?
我在xmm1
一個非常大的數字,並希望得到更高的四字r9
和較低的四字r10
,或RAX
和RDX
。
movlpd
或movhpd
只適用於reg到mem,反之亦然。
SSE2(x86-64的基準)具有在XMM和整數寄存器之間直接移動數據的指令(無需在存儲器中跳轉)。向量的低元素很容易:MOVD or MOVQ。爲了提取更高的元素,您可以將您想要的元素拖動到矢量的低元素上。
SSE4.1還爲16位以外的大小(例如PEXTRQ)添加了插入/提取。除了代碼大小,它是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是最有效的方法。即使在舊版CPU上,速度也很快,對於尺寸小於64位的元素,例如65nm Core2(Merom/Conroe),緩慢洗牌。有關詳細信息,請參見my horizontal sum answer。 PUNPCKHQDQ沒有立即數操作數,只有SSE2,所以它只有4個字節的代碼大小。
要保留xmm0的原始值,請將pshufd
用於不同的目的地。或者就地交換高低兩半,或者其他任何東西。
movlpd或movhpd ...
有一個在不斷使用它們沒有任何意義。改爲使用movlps/movhps,因爲它們更短,並且沒有CPU關心浮點數與雙精度浮點數。
您可以使用movhlps xmm1, xmm0
將xmm0的高位一半提取到另一個寄存器中,但將FP shuffle與整數向量操作混合會導致某些CPU(特別是Intel Nehalem)的旁路延遲。還要小心xmm1的依賴性導致延遲瓶頸。
肯定更喜歡pshufd
這一般。但是如果您正在調整像Core2這樣的特定CPU,那麼您可以使用movhlps
,其中movhlps
速度較快並且在整數域中運行,而pshufd
速度較慢。
用gcc(和帶有0的版本)編譯'long long f(long long __attribute __((vector_size(16)))x){return x [1];}'得到一些建議... –