从 C 代码到 RISC-V 汇编代码

Going from C code to RISC-V assembly code

我有这个练习

Translate the following C code to RISC-V assembly code. Assume that the values of a, b, i, and j are in registers x5, x6, x7, and x29, respectively. Also, assume that register x10 holds the base address of the array D.

for(i=0; i<a; i++){
    for(j=0; j<b; j++){
        D[4*j] = i + j;
    }
}

我也有评论的解决方案

Loop1:
    addi x7, x0, 0      // i = 0
    bge  x7, x5, ENDi   // while i < a
    addi x30, x10, 0    // x30 = &D[0]
    addi x29, x0, 0     // j = 0
Loop2:
    bge x29, x6, ENDj   // while j < b
    add x31, x7, x29    // x31 = i + j
    sd  x31, 0(x30)     // D[4*j] = x31
    addi x30, x30, 32   // x30 = &D[4*(j+1)]
    addi x29, x29, 1    // j++
    jal  x0,  LOOP2
ENDj:
    addi x7, x7, 1      // i++
    jal  x0, LOOP1
ENDi:

不明白的地方

sd  x31, 0(x30)     // D[4*j] = x31
addi x30, x30, 32   // x30 = &D[4*(j+1)]

sd x31, 0(x30)不是说我把x31的值存到数组30的第0位吗?哪里来的突然的4*j?

addi x30, x30, 32 不是说 x30 = x30+32 吗? x30 = &D[0] 不是在第一个循环中定义的吗? j怎么突然接触到x30了?

这相当于以下内容:

for(int64_t i=0; i<a; i++){
    int64_t* x30 = &D[0];
    for(int64_t j=0; j<b; j++){
        *x30 = i + j;
        x30 += 4; // increment by 4 elements
    }
}

x30 在循环中用作 'current pointer'。它指向 D 数组中的相关元素。它被初始化为第一个元素,并以 4 个元素为步长递增,模拟 4*j 部分。由于您的元素是 64 位,8 个字节,要增加 4 个元素,指针的基础地址应增加 4*8=32 个字节。

维护当前指针通常比每次都重新计算它更有效,尤其是在 RISC-V 中,因为你不能有寄存器偏移量(没有 str x31, [x30, x29])。