问题描述
为什么LSL的允许移位值为[0,31],LSR的允许移位值为[1,32]?
在 LSL 中移位 0 位对任何应用程序有何用处?为什么在 LSR 中不允许 0 shift?为什么 LSL 不允许 32 位移位?
解决方法
此限制适用于立即数移位。寄存器移位不受此类限制。
LSL
允许 0 表示“无移位”。这是一种特殊情况,标志设置指令的 C
标志没有被修改。
LSR
和 ASR
by 0 的行为方式与 LSL
by 0 相同,因此 CPU 设计者决定使立即操作数 0 表示移位 32,从而启用额外的功能。对于 ROR
的情况,移位 0 表示特殊的“向右旋转扩展”指令 RRX
,因为旋转 32 不是很有用。
参考例如到 ARM7TDMI 数据表,它说:
注意 LSL #0 是一种特殊情况,其中移位器进位是 CPSR C 标志的旧值。 Rm 的内容直接用作第二个操作数。
可能预期对应于 LSR #0 的移位字段的形式用于编码 LSR #32,其结果为零,Rm 的第 31 位作为进位输出。逻辑右移零是多余的,因为它与逻辑左移零相同,因此汇编程序会将 LSR #0(以及 ASR #0 和 ROR #0)转换为 LSL #0,并允许指定 LSR #32。
可能会提供 ASR #0 的移位字段的形式用于对 ASR #32 进行编码。 Rm 的第 31 位再次用作进位输出,操作数 2 的每一位也等于 Rm 的第 31 位。因此,根据 Rm 的第 31 位的值,结果是全 1 或全 0。
可能会提供 ROR #0 的移位字段的形式用于对桶形移位器的特殊功能进行编码,即右旋转扩展 (RRX)。这是通过将 CPSR C 标志附加到 Rm [...] 内容的最高有效端而形成的 33 位数量的一位位置右循环。
在 Thumb (T32) 模式下,约定进行了调整。 Thumb 缺少明显的 MOVS Rd,Rn
指令,因此使用 LSLS Rd,Rn,#0
用于此目的。 LSR Rd,#imm5
和 ASR Rd,#imm5
的行为方式与它们在 A32 模式下的行为方式相同。 #32
的立即数是通过将五位立即数字段设置为零来编码的。假设指令 ROR Rd,#imm5
不存在,因为它所在的操作码空间用于编码
ADDS Rd,Rm
SUBS Rd,Rm
ADDS Rd,#imm3
SUBS Rd,#imm3
相反。