简体   繁体   中英

64-bit sum of squares of an array of 32-bit integers on MIPS32

I have to calculate the sum of squares of an array in Mips assembly. I was looking for feedback for my code. The code posted below is just a start and doesn't take into account possible overflow situations. However, I just want to make sure, this basic block of code works as expected

# Function to calculate squared sum
# 
# Inputs:
#       $a0: address of array in memory (*a)
#       $a1: array size (n)
#
# Outputs:
#       $v0: low 32 bytes of result
#       $v1: high 32 bytes of result
#
# If the array is empty, then the function returns zero.
#

squareSum:



    Loop:

        sltu $t5,$t4,$a1    #   if(i<n)
        beq $t5,$zero,Exit  #   if ($t5 == 0)



        sll $t0,$t4,2   #   προσωρινος καταχωρητης 4 * i
        addu $t0,$t0,$a0    #   ο καταχωρητης $t0 δειχνει στη διευθυνση μνημης του array προστιθεμενο με το 4 *  i, αρα εχουμε παρει το array[i]
        lw $t1,0($t0)   #   φορτωση στον καταχωρητη $t1 της τιμη του πινακα που θελουμε καθε στιγμη
        multu $t1,$t1   #   array[i] * array[i]
        mflo $v0    #   32 least significant bits of multiplication to $v0
        mfhi $v1    #   32 most significant bits of multiplication to $v1

        addu $t2,$t2,$v0
        addu $t3,$t3,$v1

        addiu $v0,$zero,0
        addiu $v1,$zero,0

        addiu $t4,$t4,1 #   i += 1

        j Loop


        Exit:
            add $v0,$zero,$t2
            add $v1,$zero,$t3
            jr $ra

I am not sure this is how I have to handle the lo and hi of this multiplication so I want to hear some suggestions and tips

I am not sure this is how I have to handle the lo and hi of this multiplication

When you are not sure, prepare short piece of code exercising the instructions you are not completely sure, with different input values, and use debugger to step through them and clear up any confusion.

Your current usage of lo/hi after multiplication looks correct to me, works as expected in MARS simulator.

Using debugger often, trying out every new small piece of code added per single instructions, will make your progress much easier. Searching for some bug or even logical problem in big chunk of new code is often more problematic, then a-bit-tedious nature of debugging every new 4-10 lines of code right after writing them (you can put breakpoints where you need to stop in MARS simulator, and SPIM family of tools has similar features, for other MIPS platforms I'm not sure how the tools look, for regular MIPS linux + GNU toolchain you have certainly gdb available, but it's not as simple to learn as MARS, although it's much more powerful and complete).

Judging by your current source using branches in a way without branch-delay-slot, you are probably working with MARS/SPIM simulator, and you have "delayed branching" option OFF (on the real MIPS CPU the first instruction after any jump is still executed, even if the jump does branch conditionally, so on real MIPS you have to account for that either by adding nop after each jump to neutralize this behaviour, or for best performance to reorganize your code in such way, that you use the branch-delay instruction slot for actual meaningful instruction.


One thing I don't like about your code is not initializing local variables as needed... for example t4, t2, t3 . That will make your function usable only once at most, as during second try there will be already some unexpected values in registers. Maybe you left those out for brevity of your question, but in my eyes that's like plain bug of the code, those initializers should be part even of simplified minimized example code, to show that you did think your code through and you understand how it operates (and that it really needs those values).

Some more hints to make the code a bit more "optimal" and simpler: why don't you keep the running sum directly in the v0, v1, and store multiplication result into temporaries instead? You can avoid one move of result in the final part.

And you can simplify array address calculation every iteration, you can use address += 4 to update it, no need to do full (array + i*4) every time (at least you shifted that i for *4, good). If you would calculate end address ahead of loop, you can then build the whole loop condition as bne of addresses.

You have many typos in your comments, for example "32 bytes" instead of "32 bits", and similar. And I would use more explicit labels, because "loop" will probably clash with any other "loop" in somewhat larger code.

For fun I tried to follow my hints myself, and rewrite the code more to "my taste", this is the result (tried in MARS, "delayed branching" OFF, to check resulting v0:v1 value put a breakpoint after each jal ), also fixing the overflow situation:

main:   # test the subroutine
        la      $a0, testArr
        li      $a1, 4
        jal     squareSum
        # v0:v1 = 14 (0*0 + 1*1 + 2*2 + 3*3)

        # more complex input, testing 64 bit results and overflow
        la      $a0, testArr
        li      $a1, 7
        jal     squareSum

        # terminate app
        li      $v0, 10
        syscall

# Function to calculate squared sum
#
# Inputs:
#       $a0: address of word array in memory (*a)
#       $a1: array size (n)
#
# Outputs:
#       $v0: low 32 bits of result
#       $v1: high 32 bits of result
#
# If the array is empty, then the function returns zero.
#

squareSum:
        # result = 0
        addiu   $v0, $zero,0
        addiu   $v1, $zero,0
        # calculate end() pointer of array (for loop condition)
        sll     $a1, $a1, 2     # n * 4
        addu    $a1, $a1, $a0   # a1 = array.end() address (a0 = array.begin())
        beq     $a0, $a1, squareSum_exit    # begin() == end() => empty array
squareSum_summing:
        # load next array element and calculate it's square
        lw      $t0, 0($a0)     # t0 = array[i]
        addiu   $a0, $a0, 4     # advance the array pointer
        multu   $t0, $t0        # array[i] * array[i]
        mflo    $t0             # t0 = 32 least significant bits of multiplication
        mfhi    $t1             # t1 = 32 most significant bits of multiplication
        # add square value to the result
        addu    $v0, $v0, $t0
        addu    $v1, $v1, $t1
        # handle unsigned addition overflow
        sltu    $t1, $v0, $t0   # t1 = 0/1 correction ((x+y) < y)
        addu    $v1, $v1, $t1   # add correction to the result
        # loop while array_ptr != array.end()
        bne     $a0, $a1, squareSum_summing
squareSum_exit:
        jr      $ra

.data
testArr:  .word   0, 1, 2, 3, 65535, 1024, 1048576

I wrote a code for a similar problem that is quite precise and can be implemented with ease. Here I take an input n which prints the sum of product for consecutive integers starting from 1, ie array size n. Instead, what can be done is that you take the length and array both as the input and run the loop 'array length' times and the loop instead of running for n should read the elements of the array, store them then store their square, increment the address by 4 to read each index and keep saving the sum.

SUM OF SQUARES

.data
#initilisation prompt to ask the user for their input
n: .asciiz "enter n: "

.text
.globl main
main:
#declaring i and initiating its value to 0
li $t0, 0  

#printing prompt to ask from user
li $v0,4
la $a0, n
syscall

#inputing value from console
li $v0,5
syscall 
#moving to temporary variable t1
move $t1, $v0

#initialising sum as 0, stored as t3
li $t3 0
#Function acting as a loop
function:
#condition to end the loop and jump to print function
#while(t0!=t1)
    beq $t0 $t1 print
#incrementation of loop variable (t0)
    addi $t0 $t0 1
#calculating square of t0 and storing it in t4
    mul $t4 $t0 $t0
#adding the current squared to previous sum and again storing it in sum(t3)
    add $t3 $t3 $t4 
#loop to this function again
    j function

#procedure to print the sum(t3)
print:
move $a0 $t3
li $v0 1
syscall

#exit procedure
end:
li $v0 10
syscall

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