# Version history # -v0: initial version # -v1: correct mistakes in the precondition and postcondition for merge # correct the first argument of the second recursive mergesort call # -v2: implement merge. Hurray it works first time! .text main: la $a0, toSort li $a1, 9 jal mergesort li $v0, 10 syscall .data toSort: .word 3, 1, 2, 0, 2, 4, 5, -1, 9 .text # mergesort(p, n) # use mergesort technique to sort an array of integers # n integers stored at location p. # p will be passed in $a0, n in $a1 # precondition: n>=0 -- not strictly necessary # Result: p[0..n) is sorted # mergesort(p, n) { # if (n==1) return; # mergesort(p, n/2); # mergesort(p+(n/2), n-(n/2)); # #!! remember that this is pointer addition! # merge(p, n/2, n-(n/2)); # } mergesort: # prolog addiu $sp, $sp, -20 sw $ra, 0($sp) li $t0, 1 ble $a1, $t0, sortEpilog sw $a0, 4($sp) # store p sw $a1, 8($sp) # store n # set up first recursive call sra $a1, $a1, 1 # n/2 sw $a1, 12($sp) # save n/2 for later jal mergesort # set up second recursive call lw $a0, 4($sp) # p lw $a1, 8($sp) # n # move $t0, $a1 # n # sll $t0, 1 # (n/2)*4 - incorrect! lw $a1, 12($sp) sll $a1, $a1, 2 # (n/2)*4 - correct! add $a0, $a0, $a1 # address of p+(n/2) in $a0 lw $a1, 8($sp) # n lw $t0, 12($sp) # n/2 sub $a1, $a1, $t0 # n - (n/2) sw $a1, 16($sp) # save n - (n/2) for later jal mergesort # set up call to merge lw $a0, 4($sp) # p lw $a1, 12($sp) # n/2 lw $a2, 16($sp) # n - (n/2) jal merge sortEpilog: lw $ra, 0($sp) addiu $sp, $sp, 20 jr $ra # merge(p, n1, n2) # auxiliary procedure # p - pointer to an array # n1 - number of elements in first segment # n2 - number of elements in second segment # precondition p[0..n1) is sorted and # p[n1..n1+n2) is sorted # postcondition: p[0..n1+n2) is sorted # # merge(p, n1, n2) { # # # first make a copy # int tmp[n1+n2]; # Note: tmp array must be on stack and is of variable size # int *p1 = p; # use $t1 # int *p2 = tmp; # use $t2 # int *limit = &(tmp[n1+n2]) # use $t3 # for ( ; p2 < limit; p1++, p2++) { # *p2 = *p1; # } # p1 = tmp; # use $t1 # p2 = &tmp[n1]; # use $t2 # int *p1limit = p2 # use $t4 # int *p2limit = limit; # use $t5 # int *p3 = p; # use $t3 # # while (1) { # if ((p1 < p1limit) && (p2 < p2limit)) { # if (*p1 <= *p2) {w = *p1; p1++} # else { w = *p2; p2++} # } # else if (p1 < p1limit) {w = *p1; p1++} # else if (p2 < p2limit) {w = *p2; p2++} # else break # *p3 = w; p3++ # } merge: # prolog # Note: by using on $t registers we avoid having to save callee-save registers addiu $sp, $sp, -4 sw $ra, 0($sp) # main body # Acquire space on the stack for tmp array add $t0, $a1, $a2 # size of the array in words sll $t0, $t0, 2 # size of the array in bytes subu $sp, $sp, $t0 # move the sp to make the tmp array # Initialize for copying array to tmp location move $t1, $a0 # int *p1 = p move $t2, $sp # int *p2 = tmp add $t3, $t2, $t0 # int *limit = &(tmp[n1+n2]) tmpcopyloop: bge $t2, $t3, mergeinit # for ( ; p2 < limit; p1++, p2++) { lw $t8, 0($t1) # *p2 = *p1; sw $t8, 0($t2) addiu $t1, $t1, 4 # p1++ addiu $t2, $t2, 4 # p2++ b tmpcopyloop # } mergeinit: move $t1, $sp # p1 = tmp sll $t2, $a1, 2 # p2 = &tmp[n1] addu $t2, $t1, $t2 move $t4, $t2 # p1limit = p2 move $t5, $t3 # p2limit = limit move $t3, $a0 # p3 = p mergeloop: slt $t6, $t1, $t4 # p1 < p1limit slt $t7, $t2, $t5 # p2 < p2limit and $t8, $t6, $t7 # p1 < p1limit && p2 < p2 limit beq $t8, $zero, tryfirst # branch on not $t8 -- if ($t8) { lw $t8, 0($t1) lw $t9, 0($t2) bgt $t8, $t9, takesecond # if (*p1 <= *p2) { takefirst: move $t9, $t8 addiu $t1, $t1, 4 b storeresult # } else { takesecond: # value we want is already in $t9 addiu $t2, $t2, 4 # b storeresult # } tryfirst: beq $t6, $zero, trysecond # else if (p1 < p1limit) { lw $t9, 0($t1) addiu $t1, $t1, 4 b storeresult # } else trysecond: beq $t7, $zero, alldone # if p2 < p2limit { lw $t9, 0($t2) addiu $t2, $t2, 4 # b storeresult # } else break storeresult: sw $t9, 0($t3) # *p3 = w addiu $t3, $t3, 4 # p3++ b mergeloop alldone: mergeepilog: addu $sp, $sp, $t0 lw $ra, 0($sp) addiu $sp, $sp, 4 jr $ra