6

我们知道它jal指定了一个 21 位的偏移量。但是,它不编码 21 位偏移量,而是 20 位偏移量。原因是地址的最低有效位始终为零,因为可能的最小 RISC-V 指令为 2 个字节,因此该位未在指令中编码。

通过以这种方式对偏移进行编码,它可以提供 ±1MiB 的跳跃范围。如果jal确实对 LSB 进行编码,它将仅提供 ±512KiB 的跳跃范围。

但是,jalr指定 12 位偏移量的指令确实对 LSB 进行了编码。这会将跳跃范围减小到 ±2kiB(而不是 ±4kiB)。我知道它jalr使用 I 型格式,与addi这种指令的立即数的 LSB 相同,并且必须对这种指令进行编码。但是,我看不出为什么必须对最低有效位进行编码jalr

4

2 回答 2

9

JALR用于两个相对不同的目的:

  • 间接分支,例如
    • 函数返回
    • 间接函数调用(例如函数指针;vtables/虚拟调度),以及,
  • 中远分支(在两个指令序列中,具有 32 位 pc 相对范围)。

对于前者的间接分支,立即数始终为 0,也就是说实际上根本没有使用立即数!

对于后者,该指令与 结合使用AUIPC,形成 pc 相对寻址的高 20 位 -JALR然后结合使用形成低 12 位,以获得 32 位的总 pc 相对偏移量。

但是,AUIPC它既用于远分支,也用于 pc 相关数据访问。因此,它们都共享 12 位偏移量 - 加载/存储使用它们的 12 位立即数,JALR接下来也使用 12 位立即数字段,就像加载和存储一样。设计人员选择共享AUIPC而不是AUIPC为这两种用途提供两种不同的用途(从代码到代码的引用与从代码到数据的引用)。

总而言之, 的范围JALR并不重要,只要它可以提供剩余的 12 位来补AUIPC20 位即可。当然还有其他方法,但这确实具有重用和只需要一条AUIPC指令的优点。

于 2019-12-25T23:01:00.423 回答
3

基本原理已在RISC-V 规范中说明:

请注意,与条件分支指令不同,JALR 指令不会将 12 位立即数视为 2 个字节的倍数。这避免了硬件中的一种更直接的格式。在实践中,JALR 的大多数使用将立即数为零或与 LUI 或 AUIPC 配对,因此范围的轻微减少并不显着。

在计算 JALR 目标地址时清除最低有效位既可以稍微简化硬件,也可以使用函数指针的低位来存储辅助信息。尽管在这种情况下可能会丢失一些错误检查,但实际上跳转到不正确的指令地址通常会很快引发异常。

于 2020-08-27T14:56:06.137 回答