为什么 JALR 对偏移量的 LSB 进行编码?

Lui*_*Lui 6 assembly instruction-set riscv instruction-encoding

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

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

但是,jalr指定 12 位偏移量的指令确实对 LSB 进行了编码。这将跳跃范围减少到 ±2kiB(而不是 ±4kiB)。我知道它jalr使用 I 型格式,它与addi此类指令的立即数的 LSB 必须编码相同。但是,我认为没有理由必须对jalr.

Eri*_*idt 9

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

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

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

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

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

综上所述, 的范围JALR大多不重要,只要能提供剩余的 12 位对AUIPC的 20 位进行补码即可。当然还有其他方法,但这确实具有重用且只需要一条AUIPC指令的优点。