I have this exercise
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;
}
}
I also have the solution with comments
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:
What I don't understand
sd x31, 0(x30) // D[4*j] = x31
addi x30, x30, 32 // x30 = &D[4*(j 1)]
Doesn't sd x31, 0(x30)
mean that I store the value of x31 in the 0'th bit of array 30? Where does the 4*j all of a sudden come from?
And doesn't addi x30, x30, 32
mean that x30 = x30 32? And wasn't x30 = &D[0] defined in the first loop? How does j all of a sudden come into contact with x30?
CodePudding user response:
This is equivalent to the following:
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 is used as a 'current pointer' in the loop. It points to the relevant element in the D array. It is initialized to the first element, and is incremented in steps of 4 elements, which emulates the 4*j part. Since your elements are 64-bit, 8 bytes, to increment by 4 elements the underlying address of the pointer should be incremented by 4*8=32 bytes.
It is often more efficient to maintain a current pointer than recompute it everytime, especially in RISC-V, because you cannot have a register offset (there is no str x31, [x30, x29]
).