0

I want to replicate this the most cleanest way possible

In python

A = [0,0,0,0,0]
i = 0
while(i != 5):
    A[i] = 10
    i++

That is, I want to iterate through an array and sets all its values to [10,10,10,10,10]

This is what i've done in mips assembly

.data 
    array:  .word   0:5
    
.text
    
main:
    li $t1, 0       # i = 0
    la $t9, array       # $t9 = addr(array)
    li $t8, 10      # $t8 = 10
    

    
start_loop:
    beq $t1, 5, end_loop # if i == 5 jump to end loop
    
    sll $t2, $t1, 2     # $t2 = i x 4
    add $t2, $t9, $t2   # $t3 = addr(array[i])
    sw $t8, 0($t2)      # array[i] = $t8
    addi $t1, $t1, 1    # i = i + 1
    j start_loop

end_loop:

    li $v0, 10    # end program
    syscall

I feel like I used so many registers and this isn't the most clean way to do this. Any help appreciated

(Also making sure to use a loop I could hard code this without a loop but im just trying to find out other ways to use loops)

ab ce
  • 25
  • 5
  • The final fully optimized version in Craig's answer on [Translating C function with args to MIPS: loop over an int array and count negatives](https://stackoverflow.com/a/49518837) is what you should be doing. Inside the loop, only 3 instructions for your case: `sw` / `addiu` pointer increment by 4 / `bne $p, $endp, top_of_loop` (where `endp` is a pointer to 1-past-the-end you calculated earlier, ahead of the loop). Since you don't need `i` inside the loop, optimize it away. – Peter Cordes Mar 27 '21 at 13:28

2 Answers2

1
.data 
    array:  .word   0:5
    array_end:
.text
    
main:
    la     $t2, array
    addiu  $t1, $t2, 20   # one-past-end address for loop condition
                 # or  la $t1, array_end  to avoid hard-coding length
    li     $v0, 10

start_loop:                  # do{
    sw     $v0, 0($t2)          # array[i] = $t8
    addiu  $t2,$t2,4            #increment pointer after
   beq $t1, $t2, start_loop  # }while(p != endp);

#end_loop:
    #li $v0, 10         # exit call number happens to be the same value we wanted to store
    syscall             # exit

Alterations (w. help of Peter)

So the first thing that was done is removing the i variable. Instead we can compare the address of $t2, the pointer into the array, with the end-pointer we set up outside the loop ($t1), that will tell us we are done. Branching to the start_loop if not.

Pointer-increments instead of redoing the indexing every time is especially good on machines like MIPS that don't have indexed addressing modes.

Looping with the conditional branch at the bottom of the loop means you don't need a j instruction, and is idiomatic for assembly language across all(?) ISAs (e.g. Why are loops always compiled into "do...while" style (tail jump)?). It's especially good when you know the loop will definitely run at least once, so you don't need a branch ahead of the loop to maybe skip it.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
TiredButAwake
  • 157
  • 1
  • 9
  • That's an improvement, but `i` isn't needed inside the loop so you can save instructions in the loop by just doing the pointer increment. (With `bne $t1, $t2, start_loop` at the bottom as the loop branch.) See the linked duplicates of this question for better examples. Note that `beq $t1, 5` needs an internal temporary register to load a `5` into, so it's actually quite inefficient. If you were going to use a separate counter register, you'd do `addiu $t1, $t1, -1` / `bnez $t1, start_loop` at the bottom. – Peter Cordes Mar 27 '21 at 13:51
  • Yup, that's the right idea, but you still need to init `t2` to the starting pointer. So you might as well do `la $t2, array` / `addiu $t1, $t2, 20`. (Or stick a label on the end of the array and `la $t1, array_end`, so you don't have to hard-code the size anywhere, even though MARS's limited built-in assembler won't let you do stuff like `.equ arrlen, . - array` to have it compute a *length* for you.) – Peter Cordes Mar 28 '21 at 00:24
  • Also, fun optimization: you could use `$v0` to hold `10` so you need it holding a 10 later for the exit system call. – Peter Cordes Mar 28 '21 at 00:26
  • @PeterCordes thank you for this once again. Appreciated. – TiredButAwake Mar 28 '21 at 00:35
  • I edited your asm for style, e.g. remove comments that add nothing, and tidy up indentation. Also added some more explanation. Of course feel free to edit any of this into your own words; it's your answer and this is just my suggestion. – Peter Cordes Mar 28 '21 at 00:43
0
  .data
  array: .word 0:5

  .text
  main:
  li $t1, 0     #initialize i = 0
  la $t2, array #load address of array[0]
  li $t3, 10    #save 10 in a register 

  loop:
  beq $t1, 5, end       #if i == 5, end
  sw $t3, ($t2)     #array[i] = 10

  add $t2, $t2, 4   #increment array address pointer by 4
  add $t1, $t1, 1       #i = i + 1

  j loop


  end:
  li $v0, 10
  syscall
faakeha
  • 1
  • 1