מוסכמות קריאה לשגרה ב- Assembly מיון מערך (merge sort)
merge-sort אם המקרה טריוויאלי (איבר אחד או שני איברים) מיין והחזר אחרת חלק את המערך לשני חלקים ומיין כל אחד מהם לחוד (קריאה רקורסיבית) מזג את שני החלקים הממוינים
דוגמא למיון מערך תהליך דומה...
פעולת מיזוג
ממשו בשפת אסמבלי את התכנית הבאה המבצעת merge-sort בצורה רקורסיבית: #define MAX_NUM20 void main(void){ int ar[ ] = {5, 2, 16, 4, 32, 1, 8, 12, 17, 6, 7, 9, -1}; int n = 13; int br[MAX_NUM]; sort(ar, n, br); }
// Sort array A[ ] of size n to array B[ ] void sort(int A[ ], int n, int B[ ]){ int A1[MAX_NUM], A2[MAX_NUM]; int n1, n2; if (n == 1) { B[0] = A[0]; return; } else if (n == 2) { merge(A, A+1, B, 1, 1); return; } else { n1 = n/2; n2 = n - n1; sort(A, n1, A1); sort(A+n1, n2, A2); merge(A1, A2, B, n1, n2); return; }
// Merge two sorted arrays P[ ] and Q[ ] of size p and q, respectively, to array R[ ] void merge(int P[ ], int Q[ ], int R[ ], int p, int q){ int i, j, k; i = j = k = 0; while (i < p && j < q) { if (P[i] < Q[j]) R[k++] = P[i++]; else R[k++] = Q[j++]; } while (i < p) R[k++] = P[i++]; while (j < q) R[k++] = Q[j++]; }
הירארכיה בין השגרות mainsort merge sort Caller Callee
NameReg #UsePreserved on call $zero0Constant 0No $v0-$v12-3Results and expressionsNo $a0-$a34-7ArgumentsYes $t0-$t78-15TempNo $s0-$s716-23“saved”Yes $t8-$t924-25TempNo $gp28Global PointerYes $sp29Stack PointerYes $fp30Frame PointerYes $ra31Return AddressYes
תחום הכתובות אליהן ניגשים ביחס ל- $fp עבור כל שיגרה מוקצה איזור זיכרון במחסנית הנקרא frame לטובת: - העברת ארגומנטים מעבר לארבעה - שמירת תוכן הרגיסטרים אשר השיגרה הקוראת לא מעוניינת בשינוי שלהם - עבור משתנים פנימיים של השיגרה מבנה המחסנית (תזכורת)
חישוב גודל המסגרות של השגרות MainSortMerge Callee saved registers $a0 $a1 $a2 $ra $fp $a0 $a1 $a2 $a3 $ra $fp $s0 $s1 $s2 $s3 $fp Local variablesA1[MAX_NUM] A2[MAX_NUM] Frame size5*4=206*4+2*20*4=1845*4=20
sortמבנה המסגרת של השגרה
מבנה המסגרת של sort לפני הקריאה ל- merge
מימוש השגרה main main: addiu$sp, $sp, -20# stack frame size is 20 bytes sw$ra, 4($sp)# save return address sw$fp, 0($sp)# save frame pointer addiu$fp, $sp, 16# set frame pointer sw$a0, 0($fp)# save $a0 sw$a1, -4($fp)# save $a1 sw$a2, -8($fp)# save $a2 la$a0, ar# initialize the first argument lw$a1, n# initialize the second argument la$a2, br# initialize the third argument jalsort# call factorial function lw$a0, 0($fp)# restore $a0 lw$a1, -4($fp)# restore $a1 lw$a2, -8($fp)# restore $a2 lw$ra, 4($sp)# restore return address lw$fp, 0($sp)# restore frame pointer addiu$sp, $sp, 20# pop the stack jr$ra# return to caller
Sort (prologue) sort: addiu$sp, $sp, -184# stack frame size is 184 bytes sw$ra, 164($sp)# save return address sw$fp, 160($sp)# save frame pointer addiu$fp, $sp, 180# set frame pointer sw$a0, 0($fp)# save the first argument sw$a1, -4($fp)# save the second argument sw$a2, -8($fp)# save the third argument sw$a3, -12($fp)# save the fourth argument
Sort (trivial case) li$t0, 2 # if (n > 2) bgt$a1, $t0, callagain # it’s not a trivial case, go to recursive call beq$a1, $t0, simplemerge lw$t1, 0($a0)# sw$t1, 0($a2)# B[0] = A[0]; jfinishsort simplemerge: addi$a1, $a0, 4 ori$a3, $zero, 1 ori$t1, $zero, 1 addiu$sp, $sp, -4# push the fifth argument to the stack sw$t1, 0($sp) jalmerge# call merge(A, A+1, B, 1, 1) addiu$sp, $sp, 4# pop the fifth argument jfinishsort
Sort (recursive call) callagain: srl$t1, $a1, 1 move$a1, $t1 addiu$a2, $fp, -100 jalsort add$t0, $a1, $a1 add$t0, $t0, $t0 add$a0, $a0, $t0 lw$t1, -4($fp) sub$a1, $t1, $a1 addiu$a2, $fp, -180 jalsort addiu$a0, $fp, -100 addiu$sp, $sp, -4# push the fifth argument to the stack sw$a1, 0($sp) lw$t1, -4($fp) sub$a3, $t1, $a1 addiu$a1, $fp, -180 lw$a2, -8($fp) jalmerge addiu$sp, $sp, 4# pop the fifth argument
Sort (epilogue) finishsort: lw$a0, 0($fp)# save the first argument lw$a1, -4($fp)# save the second argument lw$a2, -8($fp)# save the third argument lw$a3, -12($fp)# save the fourth argument lw$ra, 164($sp)# restore return address lw$fp, 160($sp)# restore frame pointer addiu$sp, $sp, 184# pop the stack jr$ra# return to caller
merge (prologue+) merge: addiu$sp, $sp, -20# stack frame size is 20 bytes sw$fp, 0($sp)# save frame pointer addiu$fp, $sp, 16# set frame pointer sw$s0, 0($fp) sw$s1, -4($fp) sw$s2, -8($fp) sw$s3, -12($fp) li$s0, 0# i = 0 li$s1, 0# j = 0 li$s2, -1# k = -1 lw$s3, 4($fp)# $s3 = n2
while: addi $s2, $s2, 1 bge $s0, $a3, padwithQ # if (i>=n1) then goto padwithQ bge $s1, $s3, padwithP # if (j>=n2) then goto padwithP add $t0, $s0, $s0 add $t0, $t0, $t0 add $t0, $t0, $a0 lw $t3, 0($t0) add $t1, $s1, $s1 add $t1, $t1, $t1 add $t1, $t1, $a1 lw $t4, 0($t1) add $t2, $s2, $s2 add $t2, $t2, $t2 add $t2, $t2, $a2 bge $t4, $t3, storeQ sw $t4, 0($t2) # R[k] = Q[j] addi $s1, $s1, 1 # j++ j while storeQ: sw $t3, 0($t2) # R[k] = P[i] addi $s0, $s0, 1 # i++ j while
padwithP: bge $s0, $a3, finishmerge add $t0, $s0, $s0 add $t0, $t0, $t0 add $t0, $t0, $a0 lw $t3, 0($t0) add $t2, $s2, $s2 add $t2, $t2, $t2 add $t2, $t2, $a2 sw $t3, 0($t2) addi $s0, $s0, 1 addi $s2, $s2, 1 j padwithP
padwithQ: bge $s1, $s3, finishmerge add $t1, $s1, $s1 add $t1, $t1, $t1 add $t1, $t1, $a1 lw $t4, 0($t1) add $t2, $s2, $s2 add $t2, $t2, $t2 add $t2, $t2, $a2 sw $t4, 0($t2) addi $s1, $s1, 1 addi $s2, $s2, 1 j padwithQ finishmerge: lw $s0, 0($fp) lw $s1, -4($fp) lw $s2, -8($fp) lw $s3, -12($fp) lw $fp, 0($sp) # restore frame pointer addiu $sp, $sp, 20 # pop the stack jr $ra # return to caller