Reputation: 17
Can I use the 'and' operator with 'beq' in MIPS conditional statements?
For example, in C, I can write if(arr[0]=='a' && arr[1]=='b' && arr[2]=='c')
, but how can I write like this code in MIPS assembly?
Upvotes: 0
Views: 3042
Reputation: 26646
Fundamentally, we combine flow of control with logic of the conditions we're testing. As Jester is telling you, we can do/observe this in C, which is often friendlier for these transformations than assembly.
You can see that:
if(arr[0]=='a' && arr[1]=='b' && arr[2]=='c') { ... }
is equivalent to:
if (arr[0]=='a') {
if (arr[1] == 'b') {
if (arr[2] == 'c') {
/* ... */
}
}
}
So, if you know how to do if (x == y) { ... }
then just apply that three times.
In assembly language our only decision control flow construct is "if-goto", and of course only simple conditions can be tested.
So, to do if (x==y) { then-part } else { else-part }
, using an "if-goto" style, we test x==y
and upon that condition being false we branch around the then-part
and to the else-part
. Since we are branching on condition false, then when the condition is true, we fail to branch and run the then-part
that we program immediately following the condition test.
Since we're branching on condition false, then for all practical purposes, we write, in "if-goto" style in C: if (x!=y) goto ElseLabel;
followed by the then the then-part
translation...
For reference, see the following posts:
Upvotes: 3
Reputation: 30
No, you would instead just do two beq
instructions to account for both conditions.
Upvotes: 0
Reputation: 364248
No, beq
takes 2 registers and compares them, that is all. Remember, assembly language reflects what machine code can do in one instruction. Doing something more complicated often requires more instructions.
To &&
multiple conditions together, you need either
multiple beq
and/or bne
instructions; a chain of branches
or create a value in one register that represents the logical and of multiple conditions before branching. For example, load all 3 bytes and xori
them with 'a'
, 'b'
, and 'c'
respectively. (Producing 0
for a match). Then or
those results together and see if the final result is 0
(with a bne
or beq
against $zero
) If so, there were no mismatching bits in any of the 3 bytes so the condition is true.
The 2nd way optimizes away the short-circuit eval that the C logic has. Note that in the C expression, a[1]
isn't even accessed if a[0] != 'a'
, so it wouldn't fault even if a
was a pointer to the last byte of a page, and the next page was unmapped. (Assuming a[0] == 0
or something, an empty 0-terminated string).
But if you do know you can safely access all 3 bytes of the string/array, this is an option.
It's easier / more effective as an optimization when the condition is something like if (x < 5 && y < 10)
which you can implement with 2x slti
instructions to compare into registers, AND those regs together, then beq $t0, $zero, skip_if_body
In this special case where you're checking 3 contiguous bytes, it's basically memcmp(a, "abc", 3)
.
If you know that a
is word-aligned, you can do a word load to get the 3 bytes you want, plus one byte of garbage we need to ignore.
MARS simulates a little-endian MIPS system, so the 3 bytes we want are the 3 least-significant bytes in the word. (In general MIPS can run as big or little-endian.)
# assuming a[] is a word-aligned static array
# and little-endian MIPS
lw $t0, a # pseudo-instruction for lui / lw to construct the full address
li $t1, 'abc' << 8 # 0x63626100 if your assemble doesn't like multi-char literals
sll $t0, $t0, 8 # shift out the 4th byte which we need to ignore
bne $t0, $t1, skip_if_body
# if body: a[0] == 'a' && a[1] == 'b' && a[2] == 'c'
...
skip_if_body:
...
jr $ra
You can of course also use this if a
is actually a pointer in a register which is known to be word-aligned. lw $t0, ($a0)
.
I shifted the unwanted byte out of the load instead of masking it with AND because andi
can't encode 0x00FFFFFF
.
If a
wasn't known to be aligned, possibly lwl
/lwr
for an unaligned load would have been worth using.
Or lhu
+ lbu
to load 16 bits and 8 bits separately if we have 2-byte alignment; we can check 16 bits at once with xori
making use of the full width of the immediate, if we still want to combine for one branch. Or just with li
/beq
.
Constructing 'abc' << 8
in a register takes 2 instructions (lui + addiu
or ori
)
Upvotes: 0