RISC-V体系结构编程与实践(第2版)
上QQ阅读APP看书,第一时间看更新

3.5 移位操作

常见的移位操作如下。

sll:逻辑左移(shift left logical),最高位丢弃,最低位补0,如图3.10(a)所示。

srl:逻辑右移(shift right logical),最高位补0,最低位丢弃,如图3.10(b)所示。

sra:算术右移(shift right arithmetic),最低位丢弃,最高位按照符号进行扩展,如图3.10(c)所示。

图3.10 移位操作

常见的移位指令如表3.4所示。

表3.4 常见的移位指令

关于移位操作指令,有以下3点需要注意。

RISC-V指令集里没有单独设置算术左移指令,因为sll指令会把最高位丢弃。

逻辑右移和算术右移的区别在于是否考虑符号。

  例如,源操作数为二进制数10 1010 1010。

  逻辑右移一位,变成[0]1 0101 0101( 最高位永远补0)。

  算术右移一位,变成[1]1 0101 0101(需要按照源操作数进行符号扩展)。

在RV64指令集中,SLL、SRL以及SRA指令只使用rs2寄存器中低6位的数据做移位操作。

【例3-9】 如下代码使用了SRAI和SRLI指令。

li t0, 0x8000008a00000000
srai a1, t0, 1
srli t1, t0, 1

在上述代码中,SRAI是立即数算术右移指令,把0x8000 008A 0000 0000右移一位并且根据源二进制数的最高位需要进行符号扩展,结果为0xC000 0045 0000 0000。SRLI是立即数逻辑右移指令,把0x8000 008A 0000 0000右移一位并且在最高位补0,结果为0x4000 0045 0000 0000。

【例3-10】 如下代码使用了SRAIW和SRLIW指令。

1   li t0, 0x128000008a
2   sraiw a2, t0, 1
3   srliw a3, t0, 1
4
5   li t0, 0x124000008a
6   sraiw a4, t0, 1

在第2行中,使用立即数算术右移指令,截取t0寄存器低32位的值(0x8000 008A)作为新的源操作数,然后右移一位并根据新的源二进制数的最高位需要进行符号扩展,结果为0xFFFF FFFF C000 0045。

在第3行中,使用立即数逻辑右移指令,截取t0寄存器低32位的值(0x8000 008A)作为新的源操作数,然后右移一位并进行符号扩展,结果为0x4000 0045。

在第6行中,使用立即数算术右移指令,截取t0寄存器低32位的值(0x4000 008A)作为新的源操作数,然后右移一位并根据新的源二进制数的最高位需要进行符号扩展,结果为0x2000 0045。

【例3-11】 下面的示例代码使用了SLLIW指令。

1   li t0, 0x128000008a
2   slliw a3, t0, 1
3
4   li t0, 0x122000008a
5   slliw a4, t0, 1
6
7   li t0, 0x124000008a
8   slliw a5, t0, 1

在第2行中,使用立即数逻辑左移指令,截取t0寄存器低32位的值(0x8000 008A),然后左移一位,结果为0x114。

在第5行中,截取t0寄存器低32位的值(0x2000 008A),左移一位,结果为0x4000 0114。

在第8行中,截取t0寄存器的低32位的值(0x4000 008A),左移一位后为0x800 00114,由于最高位为1,需要进行符号扩展,结果为0xFFFF FFFF 8000 0114。