0

I have a C code in front of me that I have to translate into a MIPS assembly language.

I am not looking for a direct answer, but I want someone to correct the way I'm thinking about the problem.

The C code in front of me is:

x = ((++z)<=y);

I have in the given that the x, y, and z are respectively stored in the registers $6, $7, $8

The problem is I can't use an operator to compare directly less than or equal. I am limited to use the following comparing operands: bne, beq, ori, slt.

The way I approached the problem was as such:

      addi   $8,$8,1     #this will increment z by 1 to have ++z
      slt    $1,$8,$7    #compares ++z to y if ++z is < than y, it will store 1 in $1
      beq    $8,$7,Label #compares if $8 = $7, if so the code jumps to Label
Label addi   $t0,$0,1    #if ++z = y, stores 1 in $t0
      ori    $6,$t0,$1   #Or's the t0 and t1 and accordingly stores 0 or 1 in x

Is this the right approach to this problem ?

Peter Cordes
  • 286,368
  • 41
  • 520
  • 731
Ralph
  • 2,839
  • 8
  • 22
  • 47

2 Answers2

0

As usual, ask a compiler (e.g. on the Godbolt compiler explorer). See also How to remove "noise" from GCC/clang assembly output?


<= alone (without the increment) is best implemented with a reversed slt (to do b<a which is the opposite of a<=b) and then xori to flip the result.

int booleanize_le(int y, int z){
    return (z<=y);
}
# GCC5.4 -O3 -fno-delayed-branch
booleanize_le(int, int):
        slt     $2,$4,$5        # slt retval, y, z
        xori    $2,$2,0x1       # !retval, i.e. flip 0 <-> 1 since it was already boolean
        j       $31                       # return
  # (omitting the NOP in the branch-delay slot)

Fun fact: clang for RISC-V does the same thing, slt/xori, because RISC-V is like MIPS in only providing slt for compare-into-boolean. (Because you can booleanize any relation like ==, <=, >, or whatever into an integer register with at most 2 instructions.)


But in your case where you want to increment, and you're using addi so clearly z must be a signed int (otherwise your code would fault on increment from 0x7fffffffU to 0x80000000U; use addiu if you want well-defined wrap around).

C rules for signed-overflow being undefined behaviour basically match use of MIPS addi, which means compilers will also assume ++z doesn't wrap, and do the optimization we want. They and we we can just use the original z value. (z+1)<=y is the same thing as z<y if z+1 doesn't / can't wrap.

int booleanize_inc_le_signed(int y, int z){
    return ((++z)<=y);
}
booleanize_inc_le_signed(int, int):
        slt     $2,$5,$4             # z<y  before incrementing
        j       $31
    # increment optimized away in this function, but you'd do it with
    addiu   $5, $5, 1

If z had been unsigned, that optimization isn't possible and the compiler does just increment and then use the unsigned version of the 2-instruction <= slt/xori sequence:

int booleanize_inc_le_unsigned(unsigned int y, unsigned int z){
    return ((++z)<=y);
}
booleanize_inc_le_unsigned(unsigned int, unsigned int):
        addiu   $5,$5,1                # z++
        sltu    $2,$4,$5               # y<z (unsigned)
        xori    $2,$2,0x1              # return !(y<z)
        j       $31

Other relations

Exact equality, a == b

    xor     $2,$4,$5          # find bit-differences
    sltu    $2,$2,1           # (a^b) < 1U

Not equal, a != b

    xor     $2,$4,$5
    sltu    $2,$0,$2          # 0U < (a^b)

One integer being non-zero: a!=0, i.e. !!a

    sltu    $2,$0,$4          # 0U < a

Any others can obviously be derived, or just ask a compiler (use the Godbolt link).

Peter Cordes
  • 286,368
  • 41
  • 520
  • 731
-1

As pointed out by Michael, you should have the label one line below like this:

         addi   $8,$8,1
         slt    $1,$8,$7
         beq    $8,$7,Label
         addi   $t0,$0,1
Label    ori    $6,$t0,$1

What's interesting is that you use slt but not seq, why not? You probably could do that:

         addi   $8,$8,1
         slt    $1,$8,$7
         seq    $t0,$8,$7
         ori    $6,$t0,$1

And by avoiding a branch, the program can be slightly faster (assuming that case happens many times.)

Alexis Wilke
  • 17,282
  • 10
  • 73
  • 131
  • 1
    The MIPS `SLT` instruction sets the destination register to 1 if the condition is true, otherwise it sets it to zero. MIPS (MIPS32R2) does not have a `SEQ` instruction. You may be thinking of conditional move: `MOVZ`, but this is not supported in the MIPS MARS simulator. – markgz Mar 31 '14 at 18:54
  • I'm pretty sure that the `slt` instruction returned 255 for true on the SGI MIPS processors... I see that in the current documentation it says 1. Reference: http://math-atlas.sourceforge.net/devel/assembly/mips-iv.pdf – Alexis Wilke Apr 01 '14 at 17:32