0

would i write a logical AND statement the same way i would write a logical OR statement converting C to mips assembly?

else if (i == x && j == y)
printf("%c", 219);

this is what i put

bne $reg1, $t3, draw219 # i==x
bne $reg2, $t4, draw219 # j==y
David Grayson
  • 84,103
  • 24
  • 152
  • 189
dommy456
  • 1
  • 1
  • 2
    we need to see where the print and where the label draw219 are – pm100 Nov 19 '22 at 00:39
  • There's not enough code here to reason about. The C fragment is insufficient as is the assembly code. In context, this might be fine, but cannot say without that. – Erik Eidt Nov 19 '22 at 00:49
  • Basically a duplicate of [Double condition in a for loop in MIPS assembly](https://stackoverflow.com/q/13892462) which has a somewhat-explained code answer. Or [Mutiple conditions in if in MIPS](https://stackoverflow.com/q/15375267) which also has examples. Also [Multiple Conditions for an if-statement in Assembly MIPS](https://stackoverflow.com/q/72093560) – Peter Cordes Nov 19 '22 at 03:42

2 Answers2

2

We would use deMorgan as needed to convert:

Compound condition in structured if-then-else statement:

...
if ( i == x && j == y ) {
    <then-part>
}
else {
    <else-part>
}
...

In if-goto-label form, the condition is negated while also the branching is directed toward the else part, so with both of these changes together, it still runs the same (it is effectively double negation, so same logic):

        ...
        if ( ! (i == x && j == y) ) goto else1Part;
    then1Part:
        <then-part>
        goto endIf1;
    else1Part:
        <else-part>
    endIf1:
        ...

Negation can be distributed over the conjunction by negating the operands of && and changing to ||.

Application of de Morgan to the negated condition:

    if ( ! (i == x) || ! (j == y) ) goto else1Part;

And then optimize the negation of relations:

    if ( i != x || j != y ) goto else1Part;

This can the be broken into two if-statements:

    if ( i != x ) goto else1Part;
    if ( j != y ) goto else1Part;
    // will come here when the original if condition is true

And those two lines are easy in assembly.


We can convert && to & as another approach, so rather than implementing the short-circuit operator, we can evaluate both operands and simply and the results together and test that with single branch instruction.  De Morgan can also be applied; while || can be replaced with |.

Converting a short-circuit operator to non-short-circuit equivalent only works if the code allows for it, which means that it needs to be ok for the program to always perform/execute/evaluate the 2nd operand.  A function call or an array reference is not necessarily ok to perform, in the case that it is being guarded by the first condition.  Here's an example, of when it is not ok to convert short-circuit operator:

if ( i < N && a[i] == 0 ) ...

The array reference is being protected/guarded by a range check using a short-circuit operator, so it would sometimes cause an array reference out of bounds to evaluate both sides of && if it were converted to &.

Function calls in the 2nd operand can also be problematic for this conversion.

Erik Eidt
  • 23,049
  • 2
  • 29
  • 53
  • And you might actually implement it as `xor tmp1, i, x` / `xor tmp2, j, y` / `or tmp1, tmp1, tmp2` / then either `bnez` or `beqz` to branch once on the combined condition. (Where those var names are placeholders for the registers). Or on a fake / simplified MIPS where you can put two branches back-to-back (no delay slots) then yeah perhaps you'd just do that, especially since beq and bne between two non-zero registers exists. – Peter Cordes Nov 19 '22 at 03:39
  • @PeterCordes, yeah, MIPS doesn't have `seq` or `sne` (just `slt`) so that `xor` approach is nice! – Erik Eidt Nov 19 '22 at 16:37
  • xor or subu to get a 0 / non-zero is a somewhat standard technique, e.g. as part of how compilers implement `int cond = (x != y)` or `x == y` with xor/sltu on ISAs without flags. ([How to do less than or equal in Assembly Language(MIPS)?](https://stackoverflow.com/q/22736836)). Sometimes also useful for SIMD. – Peter Cordes Nov 19 '22 at 23:11
0

You accidentally inverted your logic. I'm assuming "draw219" is a piece of code equivalent to your C code printf("%c", 219);. The bne instructions should not branch there, because they only branch if the two registers are not equal. When the two registers are not equal, the overall if condition is false, so you should branch to whatever block of code you want to execute next, but don't go to "draw219".

David Grayson
  • 84,103
  • 24
  • 152
  • 189