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。