在整数 SSE 寄存器中移动更高或更低 64 位的最快方法
Posted
技术标签:
【中文标题】在整数 SSE 寄存器中移动更高或更低 64 位的最快方法【英文标题】:Fastest way to move higher or lower 64 bits in integer SSE register 【发布时间】:2015-07-02 12:13:11 【问题描述】:仅将高位或低位 64 位从整数 SSE 寄存器移动到另一个的最快方法是什么?在 SSE 4.1 中,只需一条 pblendw
指令 (_mm_blend_epi16
) 即可完成。但是旧的 SSE 版本呢?转移和拆包? AND 和 OR? movsd
尽管有绕过延迟?
密切相关的问题:Best way to shuffle 64-bit portions of two __m128i's
【问题讨论】:
【参考方案1】:将低 64 位从 src 移动到 dst,保留 dst 的高 64 位:
movsd dst, src
将高 64 位从 src 移动到 dst,保留 dst 的低 64 位:
shufps dst, src, E4h
绕过延迟通常只会增加延迟,而不是调度或执行或停用资源,因此它们通常只是在比较其他等效序列时需要考虑的问题(即,如果存在留在整数域中的单指令等效项,您会更喜欢将它用于整数运算)。
【讨论】:
谢谢。在我的例子中,movsd
最初证明与psrldq/punpcklqdq
或pshufd/punpcklqdq
一样快,但它减少了代码大小并允许重新排序指令以获得小的性能提升。看来我过于担心绕过延迟了。
有没有办法将低src
移动到高dest
,同时保持低src
?我正在从 UBsan 发现未对齐的负载,因此我需要找到 _mm_loaddup_pd
以外的其他内容。
@jww:下面是 Peter Cordes 的回答:movlhps
。【参考方案2】:
Agner Fog 的Optimizing Assembly 指南有一组很好的指令表,用于各种数据移动。 (第 13.3 节)。
要将来自两个 reg 的数据合并为一个,您的选项包括:
MOVLHPS # SSE. Low qword unchanged, high qword from low of source
MOVHLPS # SSE. Low qword from high of source, high qword unchanged
MOVSD # SSE2. Low qword from source (register only), high qword unchanged
# memory-source-only insns:
MOVLPS/D # SSE1/2. Low qword from memory, high qword unchanged
MOVHPS/D # SSE1/2. High qword from memory, low qword unchanged
SHUFPD # SSE2. Low qword from any position of destination. high qword from any position of source
PUNPCKLQDQ # SSE2. Low qword unchanged, high qword from low of source
PUNPCKHQDQ # SSE2. Low qword from high of destination, high qword from high of source
MOVQ # SSE2. Low qword from source, high qword set to zero
PBLENDW # SSE4.1
PINSRQ # SSE4.1 (only takes the low64 of src)
从 Agner Fog 的表格复制/粘贴的说明,他拥有该表格的版权。
所以shufpd
看起来是从另一个reg 插入high64 的最佳选择。其他选项将要求它位于 src 的低 64 位(对于 punpcklqdq
或 movlhps
)。
【讨论】:
关于MOVSD
,然后Intel Intrinsic Guide 说未对齐的内存很好。 _mm_load_sd
和 _mm_store_sd
状态 “mem_addr
不需要在任何特定边界上对齐”。我猜编译器正在为内部用户做一些额外的工作。
@jww: movsd
的内存源零扩展到 XMM 寄存器(是的,未对齐的地址很好,因为宽度小于 16 字节)。带有寄存器源的movsd
将低半部分合并到目标中。如果您想从内存中合并低半部分,请使用movlps
,这就是它的用途(它仅适用于内存源,而不是寄存器源。)【参考方案3】:
不知道最快的,也许是最简单的,
_mm_unpacklo_epi64(_mm_setzero_si128(), x)
[0, x0]
_mm_unpackhi_epi64(_mm_setzero_si128(), x)
[0, x1]
_mm_move_epi64(x)
[x0, 0]
_mm_unpackhi_epi64(x, _mm_setzero_si128())
[x1, 0]
【讨论】:
我想保留目标寄存器的剩余位。抱歉没有说清楚。以上是关于在整数 SSE 寄存器中移动更高或更低 64 位的最快方法的主要内容,如果未能解决你的问题,请参考以下文章