【问题标题】:Why does RV32I include instructions like ADDI and XORI but not BLTI?为什么 RV32I 包含 ADDI 和 XORI 等指令,但不包含 BLTI?
【发布时间】:2019-01-19 11:35:03
【问题描述】:

我没有 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++) {
    ...
}

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

【问题讨论】:

    标签: assembly riscv instruction-set


    【解决方案1】:

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

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

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

    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。如有必要,原始循环计数器可以与其共存(不参与循环退出测试),或者如果可能,它可以再次消失。

    【讨论】:

    • 是的。当blti 实际上是由sltbne 组成的伪指令时,在 MIPS 中也会发生同样的事情
    • 旁注:RISC-V 的bnez x, off (branch-if-not-equal-to-zero) 是一个伪指令,扩展为:bne x, x0, off
    猜你喜欢
    • 2020-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-06
    相关资源
    最近更新 更多