I am trying to write MIPS equivalent of the C code below.
int arrayData[5] = { 1,2,1,3,4 };
int K = 3;
int KCtr = 0;
int result;
bool isUnique;
for (int o = 1; o < 5; o++)
{
isUnique = true;
for (int i = 0; i < o; i++)
{
if (arrayData[o] == arrayData[i])
{
isUnique = false;
break; // goto outer loop
}
}
if (isUnique)
{
KCtr++;
}
if (KCtr==K)
{
result = arrayData[o];
}
}
I want to store the result in $s1
with the code below.
.data
Array: .word 1, 2, 4, 8, 16, 32, 64, 128
sze : .word 8
K : .word 3
.text
.globl main
main: lw $s0,K($0) # K
addi $t0,$zero,0 # index for outer loop
addi $t1,$zero,0 # index for inner loop
lw $t2,sze($0)
lw $s1,Array($0)
addi $t6,$zero,0
#addi $t7,$zero,1
#t3 for array[o]
#t4 for array[i]
#t5 for unique flag
#t6 for counter to reach K
#t7 for storing 1
outerloop:
beq $t0,$t2,finish
lw $t3,Array($t0)
addi $t5,$zero,0
innerloop:
lw $t4,Array($t1)
bne $t3,$t4,else
addi $t5,$zero,1
else:
checkifunique:
beq $t5,$t7,isnotuniquebypass
addi $t6,$zero,1
isnotuniquebypass:
addi $t1,$t1,4
blt $t1,$t0,innerloop
bne $t6,$s0,notreachedKbypass
lw $s1,Array($t0)
notreachedKbypass:
addi $t0,$t0,4
b outerloop
finish:
li $v0,10
syscall
While I am expecting to see 8
in $s1
register, I am getting 1
. What is wrong my assembly code ?
A few things were wrong.
Your C code was incomplete. By examining your asm code, I was able to add the missing stuff to the C code.
You didn't set up some registers correctly.
You were also comparing array offsets (your iteration variables that were incremented by 4) against an array index/count, so the compares wouldn't work.
You were setting the register for
KCtr
to 1, instead of doing the asm equivalent ofKCtr++
I created three examples: the fixed C code, An annotated version of your asm showing some/most of the bugs. And, a cleaned up, refactored, and working version.
Here's the C code:
Here's the annotated version:
Here's the refactored version. It's somewhat different than yours because in order to get it to work, I simplified it a bit. It also uses pointers instead of indexes or offsets for array access. Also note that once
KCtr == K
, there is no need to continue the loop.UPDATE:
ArrEnd
is a "trick" of sorts. It is the address of the last element ofArray
+ 1. That is, in C, if we haveint Array[5]
, thenArrEnd
is&Array[5]
.Just like in C, we can choose how to iterate over arrays. We can use an index and do:
Array[i]
. Or, we can useint *
pointers. In asm, we can use offsets from the start of the array (i.e. anindex << 2
).Let's recode the C program to only use pointers [and not indexes] to iterate across the array. This isn't used as often in C code, but it comes in handy for asm. The following is actually a more accurate C code representation of what my second asm example did:
Here are some idiomatic uses for
ArrEnd
:Now that we have these values, we can iterate through the array by any of the above three methods. Using the offset version or the pointer version can usually be more efficient.
To see how easy
ArrEnd
makes things, comment out the larger array and add the shorter array from the C code. TheArrEnd
trick will adjust things automatically without needing to manually count the number of elements inArray
UPDATE #2:
I may be wrong about this, but upon further reflection, to meet the requirements of the question title, the C code [and hence the asm] may need to be changed.
I think the inner loop has to scan the entire array [skipping the element where
i == o
] when looking for duplicates. Otherwise, it may hit a false positive.Also, it appears that the original never thinks the index 0 element is unique, even if it is. This is because the
o
loop started with index 1.I've created two algorithms. The original as above. And one that does the full scan. I've also added some more test cases to illustrate the issue I'm thinking of.
Here's the test program:
Here is the program output:
The simplest tests that illustrate both issues are
Array5
andArray6
Here's the corresponding asm code: