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

标签 assembly riscv instruction-set

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

关于assembly - 为什么RV32I包含ADDI和XORI等指令而不包含BLTI?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51810450/

相关文章:

assembly - 远跳到保护模式后的 GPF

architecture - RISC-V 中 JAL 的定义是什么以及如何使用它?

gdb - 如何用GDB调试交叉编译的QEMU程序?

assembly - 为什么 ARM 区分 SDIV 和 UDIV,而不区分 ADD、SUB 和 MUL?

x86 - 机器码如何存储在 EXE 文件中?

assembly - 等效于其他架构上的 Z80 DJNZ 指令?

assembly - Irvine 的 WriteString 的奇怪输出

assembly - 由于从越界内存中跳过 cmov,难以调试 SEGV

assembly - x86 汇编中的方括号是什么意思?

riscv - 学习凿子-了解火箭芯片代码的高级示例