x86帮助旋转有效位

时间:2018-02-10 00:31:56

标签: assembly x86

x是存储在ebx中的某个整数... 如何将4个最高有效位旋转1,同时保留4个最低有效位? 其中0xABCDEF12旋转到0xDABCEF12

1 个答案:

答案 0 :(得分:5)

你在谈论半字节(十六进制数字),而不是位。 4个半字节是16位, x86确实有16位操作数大小可用于旋转,因此您只需要将要旋转的位置于寄存器的低16位。

bswap  ebx      # ABCDEF12 -> 12 EF CD AB
ror    bx, 4    # CDAB -> BCDA   (high half unmodified)
bswap  ebx      # 12 EF BC DA -> DABCEF12   (partial-register stall on Core2 / Nehalem)

这对除Intel P6系列之外的所有x86 CPU where the partial-register stall sucks都有效(在编写BX后阅读EBX)。

另请注意,Core2和早期Intel P6 CPU上的bswap r32为2 uop,因此比ror r32, imm8慢。但是你要避免这种情况,因为无论如何P6系列上的部分寄存器失速。例如,在Skylake上,bswap很适合吞吐量,因为它在p1 / p5上运行,而旋转在p0 / p6上运行,所以如果你在这个序列的吞吐量上遇到瓶颈,而不是延迟,它可以与自身重叠。如果您主要与其他周围代码重叠(在右侧循环中不是这样),那么可以在ror ebx,16bswap ebx之间进行选择,以便在必要时平衡执行端口压力。 /强>

当然,如果你在一个数组的紧密循环中只是,那么首先不要加载整个元素,只需要ror word [mem+2], 4来旋转在记忆中双字的高句子。 (但是在加载 数组元素之前不要这样做,因为它会在读取 - 修改 - 写入转发结束时导致16位存储的存储转发停顿一个更宽的32位负载。如果值保留在内存中,那么内存目标旋转只是一个好主意,并且你现在所做的只是你所做的一切。)

或者,您可以移位,屏蔽和OR以将位置于它们所属的位置。我认为这将需要更多的指令,并且比3个周期的延迟链更长。 (或者是4循环on Sandybridge pre-Ivybridge, where AX is still renamed separately from RAX,但是可以插入合并的uop而不会停滞。)但是如果你需要它在Nehalem上有效的话,那就这样做吧。

AVX512F具有可变计数旋转(VPRORVD,但不适用于16位元素大小(甚至不适用于AVX512BW或AVX512VBMI),否则您可以使用计数向量将每个双字的顶部字旋转4 ,但是底部的单词是0。

AVX512VBMI2(预计在Ice Lake)有一个SIMD版本的SHLD,您可以将其用作旋转:VPSHRDVW适用于单词元素:

section .rodata
    rotate_constant:  dw 0, 4

section .text
vpbroadcastd   xmm1, [rotate_constant]   ; 32-bit broadcast of [4, 0]

# rotate the high 16-bit of every dword element in xmm0 (or ymm0 or zmm0)
vpshrdvw       xmm0,xmm0, xmm1

vpshrdvw无论如何都不能使用广播内存操作数(与dword和qword版本不同),如果它可能是16位广播,而不是32位。