【问题标题】:Fastest way to move higher or lower 64 bits in integer SSE register在整数 SSE 寄存器中移动更高或更低 64 位的最快方法
【发布时间】: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

【问题讨论】:

    标签: sse simd cpu-registers


    【解决方案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]

    【讨论】:

    • 我想保留目标寄存器的剩余位。抱歉没有说清楚。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-15
    • 2014-05-13
    • 2010-09-15
    • 1970-01-01
    • 2013-01-08
    • 2013-07-25
    • 2021-01-14
    相关资源
    最近更新 更多