简体   繁体   中英

Initialize Memory for array in risc-v

int a[10] = {1,2,3,4,5,6,7,8,9,10};

for (int i = 0;  i < 10; i++)
{
    if( a[i] > 5)
         //do something 

I would like to translate the above C code to Risc-V assembly. This is what I have so far, but I am having some confusion regarding the initialization, storage, and accessing of the array:

    #create stack
    addi sp, sp, -40
    #save s0
    sw s0, 40(sp)
    #update s0
    addi s0, sp, 40

    li x18, 1
    sw x18, -40(s0)
    li x18, 2
    sw x18, -36(s0)
    li x18, 3
    sw x18, -32(s0)
    li x18, 4
    sw x18, -28(s0)
    li x18, 5
    sw x18, -24(s0)
    li x18, 6
    sw x18, -20(s0)
    li x18, 7
    sw x18, -16(s0)
    li x18, 8
    sw x18, -12(s0)
    li x18, 9
    sw x18, -8(s0)
    li x18, 10
    sw x18, -4(s0)

    addi x5, x0, x0         //x5 = i = 0
    addi x31, x0, 10        //x31 = 10

    Func:
        //do something

    Loop: 
        lw x10, 0(s0)       //x10 = a[i] 
        bgt x10, 5, Func    //if(a[i] > 5)
        addi s0, s0, 4      //&a[i++]
        addi x5, x5, 1      //i = i + 1
        blt x5 x31, Loop    //if condition (i < 10)

Is this approach correct?

  • The control structure for the if statement is not quite right. The code is incomplete, so it is hard to tell where you're going with that. But, given that you're branching backwards to before the loop, you would have to put some extra branching in here and there.

Let's note that in the C code, the if statement is nested inside the loop, and, normally we would do the same in assembly instead of placing the then part of the if statement before and in front of the loop. The intent of the C if statement is that the then part is conditionally executed, and then when the if statement is finished, control passes to the next sequential statement after the if (here that is remainder of the loop) whether or not the if statement runs/fires the then part. If you resume control somewhere else (or only on one of condition instead of on both conditions — when the if condition is true vs. when false) your assembly code won't run like the C code.

    Loop:
        lw a0, 0(s0)
        ble a0, 5, if1IsDone  // if a[i] <= 5 then skip the "do something"

        // do something -- this is the "then" part, only runs when a[i] > 5

    if1IsDone:          // when the If is done control goes on to the rest of the loop
                        // whether the then-part executed or was skipped

        addi s0, s0, 4
        addi t0, t0, 1
        blt t0, 10, Loop

In the above, the if statement is fully nested within the loop, just like it is in the C code.

  • You're saving s0 at the top of the stack, which you don't own as it belongs to the caller. Put another way, you're allocating 40 bytes of stack space, for your local array, but you need 44 bytes of stack space for the array + the saved s0 .

  • You're creating a base pointer ( s0 ) equal to the original stack pointer and then accessing the array using negative addressing. This is both confusing and unnecessary. We can access the array from sp itself, as that is just another register. So, a[0] is at sp+0 and a[1] is at sp+4. Forwards using positive addressing.

  • Since you set up s0 to point to the end of the array, your pointer dereferencing inside the loop will not access the elements as you intend in the C code. Instead it will access the stack memory of the caller. Change to point to the beginning of the array instead, then advancing the pointer by 4 will access successive elements as you intended. (You could bias the dereference by the size of the array as a negative offset, but that would be silly compared to simply pointing to the start of the array in the first place.)

  • However, finish your C code before writing the assembly code. A small change in the C code can result in major changes to the assembly code. For example, if you have a function call inside the loop, you'd want to change the registers for values that are live across a call, probably have to save an additional registers to the stack, which could move your array and change offsets.

  • Write your assembly code true to your C code. Don't make algorithmic optimizations during translation of C to assembly.

    • If you want to use pointers instead of array indexing, then write the C code that way before taking it to assembly.
    • If you want to use a do.. while loop instead of a for loop then write the C code that way before taking it to assembly.
    • Nest control structures the same as in your C.
    • Test your C code to make sure it works because debugging algorithm design problems in assembly is hard when you don't know assembly yet.
  • As Peter says, don't mix friendly (ABI: t0,s0,sp,a0, etc..) register names with unfriendly ones (x10,x18,..) — that's super confusing. Use only friendly ABI register names. Don't use s registers unless you need them (here you don't yet).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM