int findMin( int arr[], int n ) {
int min = arr[ 0 ] ;
int i ;
for ( i = 0 ; i < n ; i++ )
{
if ( arr[ i ] < min )
min = arr[ i ] ;
}
return min ;
}
Arrays are really just pointers, and in MIPS, pointers are 32 bits
(at least, MIPS R2000/R3000---later MIPS CPUs use 64 bits of
addresses). Thus, we can pass the pointers using the argument
registers since those registers can store 32 bits.
It's often quite convenient that registers store the same number of bits as addresses.
findMin: lw $t0, 0($a0) # min = arr[0]
li $t1, 0 # i = 0
LOOP: bge $t1, $a1, END # branch ! (i < n)
add $t2, $t1, $t1 # t2 = 2 * i
add $t2, $t2, $t2 # t2 = 4 * i
add $t2, $t2, $a0 # t2 = arr + (4 * i)
lw $t3, 0( $t2 ) # t3 = arr[ i ]
bge $t3, $t0, INCR # branch ! (arr[i] < min)
move $t0, $t3 # min = arr[i]
INCR: addi $t1, $t1, 1 # i++
j LOOP # back to top of loop
END: move $v0, $t0 # retval = min
jr $ra # return
The awkward part is computing the address of the array element.
Recall that & arr[ i ] is arr + ( sizeof(int) * i ) where
we assume sizeof(int) is 4 bytes. Thus, we must compute
4 * i. There are two ways to do this. Multiply by 4 (which
involves some complications of its own) or add the number to itself
twice (which seems awkward).
Also notice where the branch statement for the if-statement goes. If the condition is false, it jumps to the increment.
la $a0, arr # set arg 0 li $a1, 10 # set arg 1 jal findMin move $t0, $v0 # save return value to $t0
int findMinTwo( int * arr, int n ) {
int min = * arr ;
int i ;
for ( i = 0 ; i < n ; i++ )
{
if ( *arr < min )
min = * arr ;
arr++ ; // POINTER ARITHMETIC: Move arr forward 1 element
}
return min ;
}
The difference in this version is that we treat the arr as a
pointer variable, and move the pointer forward one element at a time..
In the first version, findMin, we did not alter arr's value. Instead, each iteration, we computed the offset from the start of the array to element i of the array. We summed the offset and arr and storing the sum into a temporary register. Then, we loaded the array element from the address stored in this temporary register.
As you can see, the first version is more complicated to explain and implement in MIPS, even though it's somewhat easier to understand the array version than the pointer version (because most people understand arrays better than pointers, even though, in C, the two are related to one another).
findMinTwo: lw $t0, 0($a0) # min = arr[0]
li $t1, 0 # i = 0
LOOP: bge $t1, $a1, END # branch ! (i < n)
lw $t2, 0( $a0 ) # t2 = * arr
bge $t2, $t0, INCR # branch ! (*arr < min)
move $t0, $t2 # min = * arr
INCR: addi $a0, $a0, 4 # Move arr forward 1 element
addi $t1, $t1, 1 # i++
j LOOP # back to top of loop
END: move $v0, $t0 # retval = min
jr $ra # return
This code is shorter and more efficient than the array version.
This is one reason why a good knowledge of pointers can help you
write more efficient code. However, realize the tradeoffs between
efficent code, and code that's easy to follow and maintain.
If you don't mind moving the pointer (which you can do, if it's passed as a parameter), then you can avoid computing the offset, as in findMinTwo.