RISC-V 跳转指令¶
转载于RISC-V指令集讲解(5)条件和无条件跳转指令 - 知乎 (zhihu.com)
RV32I中控制转移指令主要有两类:无条件跳转和有条件跳转。
1 无条件跳转¶
无条件跳转指令均使用PC相对寻址。无条件跳转主要包括两条指令:JAL
和 JALR
。
1.1 JAL
¶
JAL
指令是用J-type格式(JAL
是RV32I中唯一J-type的指令)。
JAL
的指令格式为 JAL rd,offset
其机器码格式如图1所示。其opcode为110_1111。该指令把下一条指令的地址(PC + 4)存入rd寄存器中,然后把PC设置为当前值加上符号位扩展的偏移量。
下图为JAL
机器编码格式
注意偏移量是带符号扩展的。可以看到偏移量是2字节对齐的(offset [20:1]),虽然RV32I中所有的指令地址都是4字节对齐的,但是JAL
还可能被用于兼容C扩展指令集(详情见RISC-V 简介(4)RISC-V指令集编码结构中对其的描述),所以就默认offset bit 0为0(即2字节对齐)。
因此,JAL
跳转的地址有+/- 1MB的范围。(2^21 = 2MB = +/- 1MB)。
标准的软件调用约定(calling convention)用x1寄存器作为返回地址寄存器(rd),也可以用x5作为备用的链接寄存器(link register)。因为JAL
指令中的offset是相对于PC的偏移量,在编写时需要精确的地址差值,且任意添加/删除一条汇编指令,JAL
中的偏移量可能就需要再次修改,这给JAL
指令的使用带来了很大的负担,所以,一般在用JAL
指令时,多用JAL rd,label
而不是JAL rd,offset
。
JAL rd,label
中的label是标签,用来标注某段程序的位置,为程序中跳转及分支语句提供的跳转入口(label使用实例可以点击这里)。编译器会自动计算出标签和当前指令的offset。
1.2 JALR
¶
间接跳转指令JALR
用I-type编码类型。指令格式为JALR rd,offset(rs1)
。
相当于:
其机器码如图2所示,其opcode为110_0111,funct3为000。
该指令将PC设置为rs1
寄存器中的值加上符号位扩展的偏移量,把计算出地址的最低有效位设为0,并将原PC + 4的值写入rd寄存器。如果不需要目的寄存器,可以将rd设置为x0。
JALR
的offset也是带符号位扩展的,JALR
偏移的地址范围在rs1寄存器中存储地址的+/- 2KB(2 ^ 12 = 4096 = 4 KB = +/- 2KB)。定义JALR
指令是为了使两个指令序列可以在32位绝对地址范围内的任意位置跳转(因为JAL
指令的跳转范围不够大)。
示例:
JALR x13,0(x1)
跳到x1寄存器里存储的地址,并将下一条指令存在x13寄存器中。
一般来说,LUI
和JALR
配合使用可以跳转32位绝对地址范围,AUIPC
和JALR
配合可以跳转32位相对于PC的地址范围。
下图是JALR
机器编码格式
2 有条件分支跳转¶
所有的分支指令都是B-type编码格式,其机器码如图3所示。12位的立即数以2字节的倍数编码带符号的偏移量(offset[12:1])。
虽然RV32I中所有的指令地址都是4字节对齐的,但是JAL
还可能被用于兼容C扩展指令集,所以就默认offset bit 0为0(即2字节对齐)。
目标地址由分支指令的地址加上符号位扩展的偏移量组成,范围是2^13 = 8192 = 8 KB = +/- 4 KB。
与JAL
类似,Branch指令常见用法也可以用标签代替偏移量,比如BEQ rs1,rs2,label
。
branch指令机器编码格式如下图:
2.1 BEQ
¶
BEQ
(branch if equal,相等时分支)
其指令格式为
2.2BNE
¶
BNE
(branch if not equal,不相等时分支)
其指令格式为
2.3 BLT
¶
BLT
(branch if less than,小于时分支)
其指令格式为
2.4 BLTU
¶
BLTU
(branch if less than,unsigned,无符号小于时分支)
其指令格式为
2.5 BGE
¶
BGE
(branch if greater than or equal,大于等于时分支)
其指令格式为
2.6 BGEU
¶
BGEU
(branch if greater than or equal,unsigned,大于等于时分支)
其指令格式为