I've writen the following MIPS assembly code to test for arithmetic overflow

        add $s0, $zero, 0x80000000
        add $s1, $zero, 0xD0000000

        add $t0, $s0, $s1

MARS is translates the code above into this:

    lui $1, 0xffff8000
    ori $1, $1, 0x00000000
    add $16, $0, $1
    lui $1, 0xffffd000
    ori $1, $1, 0x00000000
    add $17, $0, $1
    add $8, $16, $17

I can't undertand why the add instructions got transformed into a lui/ori/add instrution since the constant added is 32bit and as far as I know $s0 is also 32bit. Also, where did 0xffff8000 come from? A constant in assembly is always assumed to be in two's complement, right? So why the conversion?

Thanks for the help.

The reason for the macro expansion of add in this instance is because of how the immediate instructions encode the immediate values. The actual 'add immediate' instruction, addi, is a single 32-bit value which encodes the instruction opcode itself, plus the two register arguments, and a 16-bit immediate value.

| opcode | src register | dest register | immediate value |
    6           5              5              16

This means that the addi instruction can only add a 32-bit value (from the source register) to a 16-bit immediate value. In order to handle a larger 'immediate' value, the value has to be read into the assembler temporary register ($at, register $1) in two stages: first, using 'load upper immediate' (lui) on the upper half of the immediate value, then by using 'or immediate' (ori) on that value against the lower half-word of the immediate value. This has the sum effect of loading a 32-bit value into the $at register, which is then used as the argument in the normal register to register add.

As for why it sign-extends the two values, I can only guess that it is an artifact of how the disassembly is displayed. Because both 0x8000 and 0xD000 have the uppermost bit set, the disassembler is reading them as signed values, which would normally have to sign extended as a 16-bit negative value should not become a positive value when converted to 32 bits. The fact that they are actually the upper halves of a 32-bit value is something the disassembler has no way of knowing.