0%

riscv跳转指令整理

riscv跳转指令

跳转指令可以分为: 直接跳转、寄存器跳转以及条件跳转,这几个概念并不是在一个层面上的。

直接跳转

直接跳转中,跳转的偏移直接编码在指令里,所以跳转地址是固定的。因为指令编码只有
32bit,除去指令op code,用于编码偏移的位数是有限的,所以跳转的距离也是有限的。

比如,jal rd, offset指令的格式是:

1
2
3
+---------+-----------+---------+------------+----+--------+
| imm[20] | imm[10:1] | imm[11] | imm[19:12] | rd | opcode |
+---------+-----------+---------+------------+----+--------+

它的偏移编码是20bit,所有支持跳转的范围是+/-1MB。那么如果跳转距离超过范围,就需要
把跳转的目的地址编码到寄存器里,使用如下寄存器跳转的方式完成跳转。

寄存器跳转

寄存器跳转中,跳转指令从gpr里得到跳转的目标地址,这时跳转的目的地址是动态的,跳
转的范围也足够覆盖64bit的地址空间。

riscv里使用jalr rd, offset(rs1)指令完成寄存器跳转,和上面jal一样,jalr也是带rd,
rd用来保存jalr/jal的下一条指令的地址,函数调用时,利用rd保存函数返回的地址。

使用jalr之前需要先把跳转的目的地址加载到rs1里(先认为offset是0),也就是加载一个64
bit数到一个gpr里。显然riscv 32bit的指令编码一条指令是无法搞定这个操作的。这里一般
使用auipc + addi/ld?

auipc rd, imm的意思是Add Upper Immediate to PC

1
2
3
+------------+----+--------+
| imm[31:12] | rd | opcode |
+------------+----+--------+

imm做符号扩展并左移12bit后和PC相加,结果保存到rd。可以见imm是0,可以用auipc得到PC。
如果一个符号和auipc的距离在32bit描述范围之内,编译器就可以把这个offset的高20bit
编码到auipc的imm,再用一条addi指令加上offset的低12bit,大概的示意图如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
                       +------------+----+--------+
auipc rd, imm_h | imm[31:12] | rd | opcode |
+------------+----+--------+
^ +-----------+----+-----+----+--------+
addi rd, rd, imm_l | | imm[11:0] | rs | 000 | rd | opcode |
| +-----------+----+-----+----+--------+
| ^
jalr ra, offset(rd) | |
^ | |
| +------------+-----------+
| addr offset | imm[31:12] | imm[11:0] |
| +------------+-----------+
v
label: xxx

条件跳转

条件跳转根据两个输入寄存器和判断条件决定是否跳转,可见条件跳转可以实现高级语言里
的分支语句。riscv里条件跳转的跳转偏移被直接编码到指令里,所以除去指令的op code以
及两个输入寄存器,留给offset的编码已经比较小。

比如,bge rs1, rs2, offset指令的格式是:

1
2
3
+---------+-----------+-----+-----+--------+----------+---------+--------+
| imm[12] | imm[10:5] | rs2 | rs1 | funct3 | imm[4:1] | imm[11] | opcode |
+---------+-----------+-----+-----+--------+----------+---------+--------+

它的偏移编码是12bit,所有支持跳转的范围是+/-4KB。

riscv里的条件跳转指令还有如下,可见有些比较的模式是相互之间做等价的,比如,大于
和小于的比较用一个指令就好,只要交换一下两个比较寄存器就好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
beq rs1, rs2, offset
bne rs1, rs2, offset

bge rs1, rs2, offset
bgt rs1, rs2, offset
bgeu rs1, rs2, offset
bgtu rs1, rs2, offset

blt rs1, rs2, offset
bltu rs1, rs2, offset

beqz rs2, offset
bltz rs2, offset
blez rs2, offset