在整数 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/punpcklqdqpshufd/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 位(对于 punpcklqdqmovlhps)。

【讨论】:

关于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 位的最快方法的主要内容,如果未能解决你的问题,请参考以下文章

java 374.猜数字更高或更低。哇

java 374.猜数字更高或更低。哇

java 374.猜数字更高或更低。哇

java 374.猜数字更高或更低。哇

java 374.猜数字更高或更低。哇

java 375.猜数字更高或更低II(#1递归).java