2016-12-19 230 views
4

如何將128位xmm寄存器拆分爲兩個64位四字?如何將XMM 128位寄存器分成兩個64位整數寄存器?

我在xmm1一個非常大的數字,並希望得到更高的四字r9和較低的四字r10,或RAXRDX

movlpdmovhpd只適用於reg到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。爲了提取更高的元素,您可以將您想要的元素拖動到矢量的低元素上。

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速度較慢。