-1

I'm trying to understand why mips-g++ compiles a simple division subroutine where it skips the actual div instruction with a bnez v0, <jmp> (pseudo inst for bne). My understanding is that if the divisor is zero it makes sense to skip div and trap or break in this case. Why should it branch if the divisor is not zero?

I would like to learn what I am missing.

subroutine

void do_div(int &a, int &b, int &result){
    result = a/b;
}

assembly listing :

(compiler flags: -O0)

00000000 <_Z6do_divRiS_S_>:
   0:   27bdfff8    addiu   sp,sp,-8
   4:   afbe0004    sw  s8,4(sp)
   8:   03a0f025    move    s8,sp
   c:   afc40008    sw  a0,8(s8)
  10:   afc5000c    sw  a1,12(s8)
  14:   afc60010    sw  a2,16(s8)
  18:   8fc20008    lw  v0,8(s8)
  1c:   00000000    nop
  20:   8c430000    lw  v1,0(v0)
  24:   8fc2000c    lw  v0,12(s8)
  28:   00000000    nop
  2c:   8c420000    lw  v0,0(v0)
  30:   00000000    nop
  34:   14400002    bnez    v0,40 <_Z6do_divRiS_S_+0x40>
  38:   0062001a    div zero,v1,v0
  3c:   0007000d    break   0x7
  40:   00001010    mfhi    v0
  44:   00001812    mflo    v1
  48:   8fc20010    lw  v0,16(s8)
  4c:   00000000    nop
  50:   ac430000    sw  v1,0(v0)
  54:   00000000    nop
  58:   03c0e825    move    sp,s8
  5c:   8fbe0004    lw  s8,4(sp)
  60:   27bd0008    addiu   sp,sp,8
  64:   03e00008    jr  ra
  68:   00000000    nop

  • Please try to create a proper [mcve] to show us, and include the full generated assembly from that (as *text*). – Some programmer dude May 08 '21 at 01:39
  • 1
    Please don't post pictures of text. Copy the text itself. Also, MIPS has branch delay slots. Finally, you'll find assembly to be very difficult if you try to read unoptimized compiler output. Specify `-Os` or `-O2` or `-O3` to the compiler to generate readable assembly. – EOF May 08 '21 at 01:40
  • Sure, I wanted the program address to be on the listing, for some reason godbolt wouldn't let me copy. Anyway, I compiled it myself and have updated the listing. I believe -O0 produces more readable output as there is no optimization under the hood. – Shashank Hegde May 08 '21 at 02:10
  • @EOF to give you more context, when pc is 0x34 `v0` is holding the divisor `b` from the c code and at 0x38 we are supposed to be computing v1/v0 and v1 % v0 stored in hi and and lo alu regs. Now, as b != 0, we would skip 0x38 and 0x3c and jump to 0x40. Hope this gives better context. – Shashank Hegde May 08 '21 at 02:31
  • If you didn't start out by assuming I'm wrong, you might actually have a chance to understand this problem. – EOF May 08 '21 at 07:09

1 Answers1

2

As @EOF mentioned in a comment, MIPS has the concept of branch delay slots.

This is from the description of BNE (emphasis mine):

If the contents of GPR rs and GPR rt are not equal, branch to the effective target address after the instruction in the delay slot is executed.

So the DIV always gets executed. You might think "Well, isn't that a problem if $v0 is 0?". But the description for DIV says that:

No arithmetic exception occurs under any circumstances.

If the divisor in GPR rt is zero, the arithmetic result value is UNPREDICTABLE.

So in the case of a zero divisor you end up with an unpredictable result, which we're not going to use anyway because the next thing that's done is to trigger a breakpoint exception with the BREAK instruction.

Source: MIPS32™ Architecture For Programmers Volume II: The MIPS32™ Instruction Set

Michael
  • 57,169
  • 9
  • 80
  • 125