Department of Computer Science School of Engineering and Applied Science The George Washington University CS-136: Computer Architecture II Assignment 1 "The Need for Speed": MergeSort Due Date: Midnight, Sunday, February 13, 2005 Objectives: Learn Assembly. Learn procedure calls. Practice converting "critical" code from a high level language to assembly. Structure: You've just arrived at your summer internship at foo.com. You are working as part of a team writing a program in a high-level language (C in this case...). You mention in passing that you're pretty good at assembly language. Unfortunately the team's program is REALLY slow. The team uses a program called a "profiler" to determine what section of code is responsible slowing down the program. The team discovers that the MergeSort function is really slow... You have a brilliant idea.. "Hey, I've heard that you can speed your programs up by rewriting your slowest functions in assembly!". The team rewards your CSCI136 knowledge by putting you in charge of converting the MergeSort function to MIPS assembly. The MergeSort function sorts an array of integers in to increasing order. The function works by dividing the array in to half and then calling itself with each half of the array. When MergeSort is called with a 1 element array... it knows that the array is sorted... so it simply returns. (This is known as the base case.) When the recursive calls return in to the parent function... the parent function has two sorted halves of an array. The function must combine these halves in to a single sorted array (called merging). The merge is pretty intuitive.. we'll use a temporary array to help out. We'll start at the beginning of each sorted half and use index variables to keep track of where we are in each half. We'll compare the first integer in each of the halves.. and choose the smaller value to go in to the temporary array. We'll then move the index variable ahead in the half we chose the integer from... and do another comparison and copy to the temp array. Eventually we'll reach the end of one of the halves... we'll then have to copy what is remaining of the other half in to the temporary array. After copying the remaining elements, the temporary array is sorted. We'll finish by copying the temporary array back to the original array. Lets take a look at MergeSort: The following slide is from http://www.eca.com.ve/cs/it_page/Sort_Algorithms/merge_sort.htm I used COMPUTER ALGORITHMS by Horowitz, Sahni, et. al for algorithm information. Here is the high level language implementation of MergeSort: Note C array indexs start at 0.. like Java. This program will run in Java with very minor modifications. //The arrays are "passed by reference" that is.. the address of the array is //passed to the function as a parameter instead of the actual array itself //The low and high values are "passed by value".. that is actual values are //passed to function //ourArray holds the array to be sorted //tempArray is a blank array available to use to help in merge //low holds the element number of lowest element in array //high holds the element number of the highest element in array void MergeSort(int ourArray[], int tempArray[], int low, int high) { int middle; int lowerIndex, upperIndex, newIndex; int count; //If there is only 1 element in the array... it is sorted if (low==high) { return; } middle=((high-low)/2)+low; MergeSort(ourArray,tempArray,low,middle); MergeSort(ourArray,tempArray,middle+1,high); //Now we have 2 parts of our array sorted... we now need to combine them lowerIndex=low; newIndex=low; upperIndex=middle+1; //While we haven't reached the end of a half while((lowerIndex<=middle)&&(upperIndex<=high)) { //Choose the smallest element and put it in the tempArray if (ourArray[lowerIndex]<=ourArray[upperIndex]) { tempArray[newIndex]=ourArray[lowerIndex]; //Move to next element in lower half lowerIndex=lowerIndex+1; } else { tempArray[newIndex]=ourArray[upperIndex]; //Move to next element in upper half upperIndex=upperIndex+1; } //Move to next element in the temp array newIndex=newIndex+1; } if (lowerIndex>middle) { //We finished with the lower half so we now have to finish copying the //upper part of the array in to sorted array for (count=upperIndex; count<=high; count++) { tempArray[newIndex]=ourArray[count]; newIndex=newIndex+1; } } if (upperIndex>high) { //We finished with the upper half so now we have to finish copying the //lower part of the array in to sorted array for (count=lowerIndex; count<=middle; count++) { tempArray[newIndex]=ourArray[count]; newIndex=newIndex+1; } } //finally we need to copy the temp array back to the main array for (count=low; count<=high; count++) { ourArray[count]=tempArray[count]; } } int main () { int ourArray[24]={54,23,56,32,99,7,4,2,88,9,11,21, 39,55,100,101,43,1,3,69,-5,-24,-17,0}; int tempArray[24]; MergeSort(ourArray,tempArray,0,23); } My assembly code was about ~170 lines.. about 75% of which were actual instructions (the rest were comments). I provide this figure as a rough benchmark... If you have more than ~300 lines... you probably should get help... you're probably doing something wrong. For every C instruction... there should be typically 2-3 MIPS instructions.. and at most 5. The C and Assembly versions of this program together took me about 4 hours. I estimate that the Assembly version will probably take you 6-12 hours. If you don't understand something get help! Hints: 1. Let's look at the starter code: .text .globl main main: la $a0,ourArray la $a1,tempArray li $a2,0 la $t0,arraySize lw $a3,0($t0) addi $a3,$a3,-1 jal MergeSort #the first element in the array to sort is element 0 #we have to get the actual value in there #the last element in the array to sort is size-1 done: #We're finished- so syscall to exit li $v0,10 syscall .data The main corresponds to the int main() in the C code (except we don't print). Notice that we set up the function parameters for you. There are NO parameters passed on the stack. Here's the data segment: .data #Here's our array ourArray: .word 54,23,56,32,99,7,4,2,88,9,11,21,39,55,100,101,43,1,3,69,-5,-24,-17,0 #since .space command requires #bytes, tempArray should be set to 4x the arraySize tempArray: .space 96 arraySize: .word 24 Look at how the parameters are being passed to your function: #MergeSort Function #Parameters: #$a0 holds the address of ourArray (the array of integers were going to sort) #$a1 hodls the address of tempArray (a temporary array that we can use to copy in to) #$a2 holds the value of low, which is the lowest element number of the array #$a3 holds the value of high, which is the highest element number of the array ourArray and tempArray are already set up for you in the data segment 2. You'll have to save some information on the stack before making the recursive function calls. 3. Choose your registers for your variables intelligently. You have plenty of registers... You should have register assignments figured out beforehand so you know how to adjust stack pointer and what you need to save. Required MergeSort function. A main has been provided. Functions: Output: You should be able to look at the SPIM data segment (3rd window down) and see that the array has been sorted: DATA [0x10000000]...[0x1000fffc] [0x1000fffc] [0x10010000] [0x10010010] [0x10010020] [0x10010030] [0x10010040] [0x10010050] 0x00000000 0x00000000 0xffffffe8 0xffffffef 0x00000001 0x00000002 0x00000007 0x00000009 0x00000017 0x00000020 0x00000036 0x00000037 0x00000058 0x00000063 0xfffffffb 0x00000003 0x0000000b 0x00000027 0x00000038 0x00000064 0x00000000 0x00000004 0x00000015 0x0000002b 0x00000045 0x00000065 Please note that these numbers are in HEX. (-24, -17, -5, 0, 1, 2, ...) With the following data segment here are the relevant results: .data #Here's our array ourArray: .word 354,223,156,31,99,-7,0,2,-88,9,333111,54321,39,-55,101,105,43,-1,3 #since .space command requires #bytes tempArray should be set to 4x arraySize tempArray: .space 76 arraySize: .word 19 DATA [0x10000000]...[0x1000fffc] [0x1000fffc] [0x10010000] [0x10010010] [0x10010020] [0x10010030] [0x10010040] 0x00000000 0x00000000 0xffffffa8 0xffffffc9 0x00000000 0x00000002 0x0000001f 0x00000027 0x00000065 0x00000069 0x00000162 0x0000d431 0xfffffff9 0x00000003 0x0000002b 0x0000009c 0x00051537 0xffffffff 0x00000009 0x00000063 0x000000df Can I work on other computers? Frequently Sure. We will grade using PCSpim, but there shouldn't be any problems... Asked Questions: I don't understand MergeSort. What can I do? Feel free to look on the WWW for explanations, Java, Ada and C exmaple code. Do NOT look at MIPS assembly code. Do and Do Not: Do: comment your code- recommend comments on same line out to the side instructions... helpful in SPIM use pseudo instructions (but PLEASE try to understand what is happening.. this will help you later!) use debugging features of SPIM Do Not: look at MergeSort assembly code from the WWW Some helpful functions: sll, srl, bgt, ble What to Turn in: Directions: 1. Download the merge.s file off the web. (If desired you can download merge.c file also). 2. Send an email with your final commented merge.s as an attachment to: jinfc@gwu.edu fliu@gwu.edu cheng@gwu.edu Academic Integrity: Remember the policy on academic integrity: You may discuss the assignment with others, but you are to do your own work. The official University statement for Academic Integrity, and the Department of Computer Science's policy on Academic Integrity can be accessed HERE.