为什么 RV32I 包含 ADDI 和 XORI 之类的指令而不是 BLTI?

Why does RV32I include instructions like ADDI and XORI but not BLTI?

我没有 ISA 设计经验。我一直在阅读 https://riscv.org/specifications/ 第 2 章第 21 页。

谁能解释一下为什么 RISC-V 有使用立即数的算术和逻辑指令,例如 ADDI 和 XORI,但没有类似的条件分支指令,例如 BLTI、BEQI 等

(其中 Branch Less Than Immediate 会将寄存器与常量进行比较,如果较小则分支。)

我不知情的观点是,BLTI 会经常用于 C 中的固定长度循环,例如:

for (int i = 0; i < 16; i++) {
    ...
}

为什么算术和逻辑指令比分支指令更值得立即变体?

分支已经需要将分支目标偏移量编码为立即数,在其中安装两个立即数操作数会更难。让它们都小得多可以使它们适合,但也会降低指令的有用性。

这样的分支偶尔会有用,但在我看来你高估了它的用处:在典型的循环中,没有必要直接将循环计数器与其边界值进行比较,事实上大多数循环变量甚至都没有做到这一点进入编译后的代码。

作为一个小例子(使用更高的计数来避免循环的完全展开),

int test(int *data) {
    int sum = 0;
    for (int i = 0; i < 255; i++)
        sum += data[i];
    return sum;
}

被Clang编译成:

test(int*):                              # @test(int*)
    addi    a2, zero, 1020
    mv      a3, zero
    mv      a1, zero
.LBB0_1:                                # =>This Inner Loop Header: Depth=1
    add     a4, a0, a3
    lw      a4, 0(a4)
    add     a1, a4, a1
    addi    a3, a3, 4
    bne     a3, a2, .LBB0_1
    mv      a0, a1
    ret

Clang 在这里所做的是计算最终的 地址 然后循环直到到达该地址,从存在中删除循环计数器。

这是一个有点特殊的情况,但也有其他技巧。例如,在很多情况下,循环退出测试可以转化为当寄存器递减为零时退出的循环,这很容易测试,因为RISCV有bnez。如果有必要,原始循环计数器可以与它共存(不参与循环退出测试),或者如果可能,它可以再次消失。