我一直想知道一些CPU上具有旋转指令(例如x86上的ROL、RCL)的目的是什么。有哪些软件会使用这些指令呢?
起初,我认为它们可能用于加密/计算哈希代码,但这些库通常是用C编写的,而C没有将运算符映射到这些指令中。(编辑说明:请参见C++中循环移位(旋转)操作的最佳实践,了解如何编写可编译为旋转指令的C或C++。此外,优化后的加密库通常确实具有特定平台的汇编代码。)
有人发现过它们的用途吗?它们为什么被添加到指令集中?
我一直想知道一些CPU上具有旋转指令(例如x86上的ROL、RCL)的目的是什么。有哪些软件会使用这些指令呢?
起初,我认为它们可能用于加密/计算哈希代码,但这些库通常是用C编写的,而C没有将运算符映射到这些指令中。(编辑说明:请参见C++中循环移位(旋转)操作的最佳实践,了解如何编写可编译为旋转指令的C或C++。此外,优化后的加密库通常确实具有特定平台的汇编代码。)
有人发现过它们的用途吗?它们为什么被添加到指令集中?
对于跨越多个字的位移操作,需要进行旋转操作。当通过SHL移动低位时,高阶位溢出到进位标志CF中。为了完成操作,需要将高位字移位同时将进位带入低位。RCL指令可以完成此操作。
高位字 低位字 CF 初始值 0110 1001 1011 1001 1100 0010 0000 1101 ? SHL低位字 0110 1001 1011 1001 1000 0100 0001 1010 1 RCL高位字 1101 0011 0111 0011 1000 0100 0001 1010 0
ROL和ROR用于以最终非破坏性方式逐位检查值。它们也可用于在不引入垃圾位的情况下移动掩码。
BT
? - Gabe旋转移位指令 ROL、RCL、ROR 和 RCR 几乎完全用于哈希和 CRC 计算。它们相当晦涩,很少使用。
移位操作码(SHL、SHR)用于快速乘以2的幂,或将低字节移动到大寄存器的高字节中。
ROL 和 SHL 的区别在于 ROL 获取高位并将其滚动到低位位置。SHL 放弃高位,并用零填充低位位置。
popcnt
或 crc32
或 SIMD psadbw
不同,后者基本上是为视频编码运动搜索添加的),但另一方面,使旋转位移器能够旋转并不需要太多额外的硬件。 - Peter CordesROR和ROL是“历史悠久”的指令,但在许多方面仍然很有用。
在80386(和操作码BT)之前,ROL经常用于测试一个位(SHL不会传播到进位标志)- 实际上,在8088中,ROR/ROL每次只能移动1个位!
此外,如果您想要先向一侧移位,然后再向另一侧移位而不失去已超出范围的位,则应使用ROR/ROL,而不是SHR/SHL。
cl
中给定的计数进行旋转。(除1以外的立即字节移位/旋转计数是在186指令集中添加的。) - ecm早期的微处理器时代,大部分程序都是采用汇编语言编写而非编译。大多数CPU指令可能并不是由编译器发出(这也是创建RISC的动力所在),但通常相对容易在硬件中实现。
图形学和密码学中的许多算法使用旋转,它们被包括在CPU中,可以在汇编中编写非常快速的算法。
rotate all bits left by 3
hi lo
src = fedcba98|76543210
dst = cba98765|43210---
注意,位“765”需要向右移动5位,而位“43210”需要向左移动3位。这可以通过一个旋转来完成,将所有正确的位放到正确的位置,即使它们与错误的位一起出现,也可以通过掩码重新组合,这是一种廉价的操作:
dst_lo = ((src_lo ROL 3) & 0b11111000)
dst_hi = ((src_lo ROL 3) & 0b00000111) | (src_hi << 3)
这也适用于大整数移位,或通过任意数量的像素水平滚动单色图形平面。
这个算法非常重要,以至于80386为此包含了一个双旋转指令。
src_hi << 3
而不是ROL + mask,因为在那里移出的位没有被移入任何东西中。 - Peter Cordes
(x << 12) | (x >> 20)
)时,会发出rol
操作码。 - Thomas Porninrol
,我的意思是rol
(好吧,也可能是ror
)。旋转操作码。 - Thomas Pornin<<
和>>
是位移操作。但对于一个32位的值x
,整个表达式(x << 12) | (x >> 20)
包含两个位移操作(一个左移,一个右移)和一个按位或操作,其效果相当于将一个32位字(在这里向左旋转12位)。C编译器足够聪明,能够注意到这一点,并将整个表达式编译为单个rol
指令。 - Thomas Pornin