Search code examples
mipsdivide

In MIPS, how do I divide register contents by two?


Let's say I have $t0, and I'd like to divide its integer contents by two, and store it in $t1.

My gut says: srl $t1, $t0, 2

... but wouldn't that be a problem if... say... the right-most bit was 1? Or does it all come out in the wash because the right-most bit (if positive) makes $t0 an odd number, which becomes even when divided?

Teach me, O wise ones...


Solution

  • Use instruction sra: Shift right arithmetic !!

    sra $t1, $t0, 1
    

    Divides the content of $t0 by the first power of 2.

    Description: Shifts a register value right by the shift amount (shamt) and places the value in the destination register. The sign bit is shifted in.

    Operation: $d = $t >> h;

    advance_pc (4);

    Syntax: sra $d, $t, h

    Encoding: 0000 00-- ---t tttt dddd dhhh hh00 0011

    Why is this important? Check this simple program that divides an integer number (program's input) by 2.

        #include <stdio.h>
    
        /*
        * div divides by 2 using sra
        * udiv divides by 2 using srl
        */
        int div(int n);//implemented in mips assembly.
        int udiv(int n);
        int main(int argc,char** argv){
    
                if (argc==1) return 0;
                int a = atoi(argv[1]);
    
                printf("div:%d udiv:%d\n",div(a),udiv(a));
                return 1;
        }
        //file div.S
        #include <mips/regdef.h>
    
        //int div(int n)
        .globl div 
        .text
        .align 2
        .ent div
        div:
                sra v0,a0,1
                jr  ra        //Returns value in v0 register.
        .end div
    
        //int udiv(int n)
        .globl udiv
        .text
        .align 2
        .ent udiv
    
       udiv:
         srl v0,a0,1
         jr  ra        //Returns value in v0 register.
       .end udiv
    

    Compile

    root@:/tmp#gcc -c div.S
    root@:/tmp#gcc -c main.c
    root@:/tmp#gcc div.0 main.o -o test
    

    Test drives:

    root@:~# ./test 2
    div:1 udiv:1
    root@:~# ./test 4
    div:2 udiv:2
    root@:~# ./test 8
    div:4 udiv:4
    root@:~# ./test 16
    div:8 udiv:8
    root@:~# ./test -2
    div:-1 udiv:2147483647
    root@:~# ./test -4
    div:-2 udiv:2147483646
    root@:~# ./test -8
    div:-4 udiv:2147483644
    root@:~# ./test -16
    div:-8 udiv:2147483640
    root@:~#
    

    See what happens? The srl instruction is shifting the sign bit

    -2 = 0xfffffffe

    if we shift one bit to the right, we get 0x7fffffff

    0x7ffffffff = 2147483647

    Of course this is not a problem when the number is a positive integer, because the sign bit is 0.