Search code examples
cassemblymipstranslate

MIPS ASSEMBLY How to use if's and else's translation from C to MIPS Assembly


So i have this code in C that i have to translate into assembly

    int a[10]={0,1,2,3,4,5,6,7,8,9};
    int i, j, k;
    i = 1;
    goto abc;
def:
        j = 1;
        k = 4;
    goto ghi;
    i = 2;
abc:
    goto def;
ghi:
    if (i==j){
        a[2] = a[3];
    }else{
        a[2] = a[4];
    }
    while(k>0){
        a[k] = 7;
        k = k - 1;
    }
    if((i>k) && (i<10)){
        if((k==6) || (j>=i)){
            a[9] = 400;
        }else{
            a[9] = 500;
        }
    }
    switch(j){
        case 0: a[6] = 4; break;
        case 1: a[6] = 5; break;
        case 2: a[6] = 6; break;
        case 3: a[6] = 7; break;
    }
    

I have been able to turn only the goto parts into assembly because i don't know how to turn the if's else's and switch commands into MIPS assembly Here what i have done so far

.text
main:
    li  $t0, 1
    lw  $t0, variableI      ## i = 1
    j abc               ## goto abc
def:
    li  $t0, 1
    lw  $t0, variableJ      ## j=1
    li  $t0, 4
    lw  $t0, variableK      ## k=4
    j ghi               ## goto ghi
    li  $t0, 2
    lw  $t0, variableI      ## i = 2
abc:
    j def               ## goto def
ghi:
    
    

.data
variableI:  .word
variableJ:  .word
variableK:  .word
vetorA:     .word 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

It isn't necessary to translate all code for me just need a good explanation of how to use if's and else's since i haven't found any really good explanation online.


Solution

  • The instruction set manual is online that will cover all of it. As well as compilers.

    unsigned int fun ( unsigned int a, unsigned int b, unsigned int c )
    {
        unsigned int r;
        
        r = 0;
        if(a==5)
        {
            r=6;
        }
        return(r);
    }
    
    mips-elf-gcc -O2 -c -fno-delayed-branch so.c -o so.o
    mips-elf-objdump -d so.o
    
    so.o:     file format elf32-bigmips
    
    
    Disassembly of section .text:
    
    00000000 <fun>:
       0:   24020005    li  $2,5
       4:   10820004    beq $4,$2,18 <fun+0x18>
       8:   00000000    nop
       c:   00001025    move    $2,$0
      10:   03e00008    jr  $31
      14:   00000000    nop
      18:   24020006    li  $2,6
      1c:   03e00008    jr  $31
      20:   00000000    nop
    

    equals and not equals are easy, bne, beq...

    it is often common for the compiler to generate the opposite something like this in this case

    return reg = 0;
    compare input reg with 5
    if NOT equal then branch to skip
    return reg = 6
    skip:
    return
    

    But not always, gcc did this

       0:   24020005    li  $2,5
       4:   10820004    beq $4,$2,18 <fun+0x18>
       8:   00000000    nop
    

    r2 is the return register load it with a 5 as a temporary register for now in order to do the comparision. compare the input reg (r4) with 5 if equal then branch to address 18. If not equal keep going.

    If not equal then

       c:   00001025    move    $2,$0
      10:   03e00008    jr  $31
      14:   00000000    nop
    

    put a 0 in the return register r2 and return. this path is the equivalent of

    r = 0;
    return(r);
    

    If it is equal to 5 then

      18:   24020006    li  $2,6
      1c:   03e00008    jr  $31
      20:   00000000    nop
    

    put the 6 in r2 and return

    For this example C code the compiler is very brute force about the solution, other than not incurring more branches to have a single exit point (not-atypical).

    unsigned int fun ( unsigned int a, unsigned int b )
    {
        unsigned int r;
        
        r = a;
        switch(b)
        {
            case 5: r+=3; break;
            case 7: r^=3; break;
        }
        return(r);
    }
    

    sometimes you will see the tools generate a jump table, depends on the architecture and other factors, in this case that is not going to happen but if you had switch(b&3) and then the four possible cases, I tried and gcc did not make a jump table.

    But what is a switch really? in this case and in all cases it is no more than if (argument in the parens, in this case just b by itself) b is 5 else of b is 7 then. A switch is an if-then-else tree and often that is all a compiler will bother to implement.

    00000000 <fun>:
       0:   24030005    li  $3,5
       4:   00801025    move    $2,$4
       8:   10a30009    beq $5,$3,30 <fun+0x30>
       c:   00000000    nop
      10:   24030007    li  $3,7
      14:   14a30004    bne $5,$3,28 <fun+0x28>
      18:   00000000    nop
      1c:   38820003    xori    $2,$4,0x3
      20:   03e00008    jr  $31
      24:   00000000    nop
      28:   03e00008    jr  $31
      2c:   00000000    nop
      30:   24820003    addiu   $2,$4,3
      34:   03e00008    jr  $31
      38:   00000000    nop
    

    r = a

       4:   00801025    move    $2,$4
    

    if b == 5 then

       0:   24030005    li  $3,5
    
       8:   10a30009    beq $5,$3,30 <fun+0x30>
       c:   00000000    nop
    

    r+=3 and return

      30:   24820003    addiu   $2,$4,3
      34:   03e00008    jr  $31
      38:   00000000    nop
    

    (else) if b==7

      10:   24030007    li  $3,7
      14:   14a30004    bne $5,$3,28 <fun+0x28>
      18:   00000000    nop
    

    r ^=3 and return

      1c:   38820003    xori    $2,$4,0x3
      20:   03e00008    jr  $31
      24:   00000000    nop
    

    else return (r was set to a up front)

      28:   03e00008    jr  $31
      2c:   00000000    nop
    

    so it is a simple if-then-else tree with one non brute force out of order kind of thing the r = a was placed in the middle of the if b == 5 were mixed together.

    unsigned int fun ( unsigned int a )
    {
        unsigned int r;
        
        r = 0;
        if(a<5)
        {
            r = 3;
        }
        return(r);
    }
    
    
    00000000 <fun>:
       0:   2c840005    sltiu   $4,$4,5
       4:   14800004    bnez    $4,18 <fun+0x18>
       8:   00000000    nop
       c:   00001025    move    $2,$0
      10:   03e00008    jr  $31
      14:   00000000    nop
      18:   24020003    li  $2,3
      1c:   03e00008    jr  $31
      20:   00000000    nop
    

    because of how mips works or at least the mips I have compiled for

    set if less than unsigned

       0:   2c840005    sltiu   $4,$4,5
    

    since the way the C was written we can actually discard the a variable with the if less than question. So if r4 (a) is less than 5 then "set" r4 (non-zero)

    so now less than becomes an equal or not equal question

    if(r4 is not equal to zero) combined with the above means if a is less than five then

       4:   14800004    bnez    $4,18 <fun+0x18>
       8:   00000000    nop
    

    return 3

      18:   24020003    li  $2,3
      1c:   03e00008    jr  $31
      20:   00000000    nop
    

    else return 0

       c:   00001025    move    $2,$0
      10:   03e00008    jr  $31
      14:   00000000    nop
    

    Mips doesn't like/use flags like most other instruction sets. Most others you would have a compare instruction which does a subtract and sets a bunch of flags but does not store the subtraction to a register, then subsequent instructions will use those flags. mips uses a philosophy of no flags so do the comparison and act on it in the same instruction. So for example another architecture:

    00000000 <fun>:
       0:   e3500004    cmp r0, #4
       4:   93a00003    movls   r0, #3
       8:   83a00000    movhi   r0, #0
       c:   e12fff1e    bx  lr
    

    compare a with 4 then if less than or same r = 3 if higher r = 0 and return. This is in a way also very atypical in that this instruction set shown here (arm) allows for per-instruction conditional execution rather than only branches are conditional and mov and add and such are not.

    And this is more typical

    00000000 <_fun>:
       0:   0a00            clr r0
       2:   2d97 0002 0004  cmp 2(sp), $4
       8:   8301            blos    c <_fun+0xc>
       a:   0087            rts pc
       c:   15c0 0003       mov $3, r0
      10:   0087            rts pc
    

    and this is almost brute force one to one

    r = 0

       0:   0a00            clr r0
    

    compare a (passed in on the stack) with 4

       2:   2d97 0002 0004  cmp 2(sp), $4
    

    branch if lower or same to address c:

       8:   8301            blos    c <_fun+0xc>
    

    if 5 or higher then return (with r = 0)

       a:   0087            rts pc
    

    if less than 5 (less than or equal to 4) then return 3

       c:   15c0 0003       mov $3, r0
      10:   0087            rts pc
    

    (destination is on the right here mov $3,r0 means r0 = 3. $ means constant here)