Assembly Summation Implementation I wrote a simple summation program in MARS to practice using loops and jump instructions. I feel like this is pretty lightweight and wanted some feedback on possible improvements:


Lowering instruction count
Organizational changes


Am I correct in assuming this is a "do-while" loop?

# Description: Summation program implementing a do-while loop
# Author: Evan Bechtol

        .data
Prompt: .asciiz "Enter number to get summation: "
Output: .ascii  "Sum of numbers is: "
        .globl main
        .text
main:
    # Prompt for input
    li   $v0, 4
    la   $a0, Prompt
    syscall

    # Read input
    li   $v0, 5
    syscall
    add  $s0, $zero, $v0

    # Begin summation
    addi $s1, $zero, 1 # $s1 used to store summation, starts at 1
    addi $t1, $zero, 1 # $t1 used as counter, starts at 1
    jal  loop          # Go to loop 

    # Display
    li   $v0, 4
    la   $a0, Output
    syscall

    li   $v0, 1
    add  $a0, $zero, $s1
    syscall

    # Exit
    la   $v0, 10
    syscall

loop:
    addi $t1, $t1, 1
    add  $s1, $s1, $t1
    bne  $t1, $s0, loop
    jr   $ra
I see a number of things that might help you improve your program.

Use li rather than la to load a constant

As has already been noted, the la $v0, 10 instruction should actually be li $v0, 10.  It works that way because you're loading the address 10 into $v0 which has the same effect, but it's a little strange looking.

Put the $zero at the end of the instruction

The instruction add  $s0, $zero, $v0 is perfectly valid, but it might look a little odd to those experienced with MIPS assembly language.  The typical idiom that I've seen is to put the constant at the end, so that instruction would instead read add  $s0, $v0, $zero which does exactly the same thing, but I find it easier to pick out the $zero at the end rather than in the middle.  That's purely a stylistic suggestion, though.

Minimize register use

You don't really need both a counter and a number.  What you can do instead is to use the original input number in $s0 as the counter and decrement instead of incrementing.  

Avoid the overhead of subroutine calls

There's nothing wrong with using subroutines, of course, but they add cycles to the program, and for such a small and simple program as this, the call isn't really necessary.  Instead, you could put the loop inline.

Prefer to branch at the end of a loop

A while... loop in higher level languages does not even execute once if its condition is false.  A do ... while loop executes at least once, which seems to me to be what is desired here.  You can then minimize branching so that there is only one conditional branch at the end of the loop.

Use a better algorithm

Carl Friedrich Gauss came up with a clever algorithm as a child.  You can read about it and see if you can implement it for even faster code.

Putting it all together

When we apply all but the last suggestion, we get something like this:

        .data
Prompt: .asciiz "Enter number to get summation: "
Output: .ascii  "Sum of numbers is: "
        .globl main
        .text
main:
    # Prompt for input
    li   $v0, 4
    la   $a0, Prompt
    syscall

    # Read input
    li   $v0, 5
    syscall
    add  $s0, $v0, $zero  # s0 used as loop countdown
    add  $s1, $s1, $zero  # s1 used for summation = 0
loop:
    add  $s1, $s1, $s0    # add number to summation

    # Begin summation
    addi $s0, $s0, -1     # decrement number
    bgtz $s0, loop        # keep going until 0

        # Display
    li   $v0, 4
    la   $a0, Output
    syscall

    li   $v0, 1
    add  $a0, $s1, $zero
    syscall

    # Exit
    li   $v0, 10
    syscall