ARM NEON技术问询:如何对64位d寄存器执行整体位移位?
解决64位NEON d寄存器的寄存器指定逻辑移位问题
Hey, I get exactly what you're dealing with here—ARM NEON's vshl and vshr instructions operate per-element, meaning they only shift bits within each 64-bit element of the register, never crossing element boundaries to treat the entire d-register as a single 64-bit integer. That's obviously not what you need for a full-register logical shift where the count comes from another register.
Let's break down the best solutions depending on your architecture:
方案1:借助通用寄存器(最推荐,简单高效)
通用寄存器(AArch64的x寄存器、AArch32的r寄存器)天生就是为整数移位这类操作设计的,这是最直接高效的方案,步骤如下:
- 将NEON d寄存器的64位值转移到通用寄存器中
- 用通用寄存器的逻辑移位指令(左移
lsl、右移lsr)完成操作,移位位数由另一个通用寄存器提供 - 将结果移回NEON d寄存器
AArch64 示例代码
; 假设: ; - d0 = 要移位的64位整数值 ; - x1 = 移位位数(0 ≤ x1 < 64) mov x0, d0 ; 将d0的64位值转存到通用寄存器x0 lsl x0, x0, x1 ; 逻辑左移x1位,左端补0(替换为`lsr x0, x0, x1`做右移,右端补0) mov d0, x0 ; 把移位结果转回d0寄存器
AArch32 示例代码
AArch32通用寄存器是32位,需要拆分64位d寄存器到两个32位通用寄存器后再组合:
; 假设: ; - d0 = 要移位的64位整数值 ; - r2 = 移位位数(0 ≤ r2 < 64) vmov r0, r1, d0 ; 将d0拆分为低32位(r0)和高32位(r1) ; 处理64位逻辑左移(替换为对应逻辑右移逻辑即可) mov r3, r2 cmp r3, #32 blt .L_shift_less_32 ; 移位位数≥32的情况 sub r3, r3, #32 mov r0, r1, lsl r3 mov r1, #0 b .L_shift_done .L_shift_less_32: ; 移位位数<32的情况 mov r0, r0, lsl r3 orr r0, r0, r1, lsr #(32 - r3) mov r1, r1, lsl r3 .L_shift_done: vmov d0, r0, r1 ; 把组合后的64位结果转回d0
方案2:纯NEON指令实现(仅当无法使用通用寄存器时)
如果因为特殊限制不能用通用寄存器,可以用NEON的向量操作和位指令模拟全寄存器移位,这种方法更复杂且性能更低,但可以实现需求:
- 将64位d寄存器扩展为128位q寄存器,高位补0
- 将移位位数拆分为字节移位量和剩余位移位量
- 用字节提取指令
vext处理字节对齐的移位 - 结合位移位
vshl/vshr和或运算处理跨元素的剩余位移位
AArch64 示例代码
; 假设: ; - d0 = 要移位的64位值 ; - d1 = 存储移位位数的寄存器(低6位有效) mov w1, v1.s[0] ; 提取移位位数到通用寄存器w1(仅用于计算,可替换为NEON标量操作) and w1, w1, #63 ; 确保位数在0-63之间 mov w2, w1, lsr #3 ; 计算字节移位量:shift_count // 8 mov w3, w1, & #7 ; 计算剩余位移位量:shift_count % 8 ; 扩展d0到128位,高位补0 mov v0.2d[1], #0 ; 字节级左移,补0 mov v1.16b, #0 vext v0.16b, v0.16b, v1.16b, w2 ; 处理剩余位的跨元素移位 mov v2.16b, v0.16b vshl v2.16b, v2.16b, v3.16b vshr v0.16b, v0.16b, #(8 - w3) orr v0.16b, v0.16b, v2.16b ; 取低64位作为结果 mov d0, v0.d[0]
关键要点
vshl/vshr不适用的核心原因是它们是按元素操作的指令——只会在寄存器的每个64段子内部移位,不会把整个64位寄存器当作单一整数处理- 通用寄存器中转的方案几乎是最优选择:代码简洁、性能更高、调试更简单
内容的提问来源于stack exchange,提问作者Florian S
相关产品推荐
相关产品推荐

