为什么RV32I包含ADDI和XORI等指令而不包括BLTI?

fad*_*bee 3 assembly isa riscv

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

有人可以解释为什么RISC-V具有使用immediates的算术和逻辑指令,例如ADDI和XORI,但不是类似的条件分支指令,例如BLTI,BEQI等.

(Branch Less Than Immediate会将一个寄存器与一个常量进行比较,如果它更少则将其分支.)

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

for (int i = 0; i < 16; i++) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

har*_*old 8

分支已经需要将分支目标偏移编码为立即,在那里拟合两个立即操作数将更难.使它们都小得多可以使它们适合,但也会降低指令的实用性.

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

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

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

由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
Run Code Online (Sandbox Code Playgroud)

Clang在这里做的是计算最终地址,然后循环直到达到该地址,从而消除循环计数器.

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

  • 是.当"blti"实际上是由`slt`和`bne`组成的伪指令时,MIPS也会发生同样的事情 (2认同)