MIPS Inline Assembly Language Examples

The MIPS instruction set is designed to be used with optimizing compilers. The MIPS compiler (CLMIPS.EXE) for Visual C++ generates high-quality MIPS assembly-language code. Therefore, use __asm statements only when necessary. While the examples shown here illustrate the use of __asm statements, they are not inherently any more efficient than the code typically produced directly by the Visual C++ compiler.

The MIPS edition of the compiler allows you to use the __asm statement to write macros that you can call from within C or C++ source code. The syntax of the __asm statement makes such macros possible because of its flexible support for arguments. As illustrated in the following example, you do not need to fix argument values, but can specify them at the time of macro expansion. However, call a macro such as this only from within C or C++ functions.

In the following example, a sample function named my_mult takes two unsigned 32-bit integer arguments, a and b, and multiplies them together. The product is stored at the location specified by the third argument, c, which is a pointer to a 32-bit argument. The function also determines what the overflow portion of the multiplication is, if any, and returns the overflow portion through its return value.

extern "C" { // Use extern "c" for C++ file only 
void __asm(char*, ...); 
}; 
#pragma intrinsic(__asm) // this is actually optional 
long my_mult(long a, long b, long* c) { 
long overflow; 
__asm("mult $4,$5"); 
__asm("mflo $4"); 
__asm("sw $4, 0($6)"); // store product 
__asm("mfhi $11"); 
__asm("sra $12,$4, 31"); 
__asm("sne $12,$12,$11"); 
__asm("sw $12, 0(%0)", &overflow); // store overflow 
return(overflow); 
} 

Because the preceding example does not use conditional compilation, the code is not portable to all MIPS platforms. To make it portable, #ifdef blocks would have to be used.

The preceding example function places its arguments a, b, and c in the registers $4, $5, and $6, respectively. These are the first three argument registers; they can also be referred to as a0, a1, and a2.

The local variable overflow is defined in C or C++ code. Inline assembly code can easily recognize variables defined in C or C++ statements because of the __asm argument-handling feature. The expression &overflow is referred to as the argument %0 in the string portion of the following statement:

asm("sw $12, 0(%0)",&overflow); // store 

The following example shows how to us the __asm statement with multiple instructions separated by semicolons (;) and explicitly coded new-lines (\n).

extern "C" { // Use extern "c" for C++ file only 
void __asm(char*, ...); 
}; 
long my_mult(long a, long b, long* c) { 
long overflow; 
__asm("mult $4,$5;" 
"mflo $4;" 
"sw $4, 0($6);" // store product 
"mfhi $11;" 
"sra $12,$4, 31;" 
"sne $12,$12,$11;" 
__asm("sw $12, 0(%0)", &overflow); // store overflow 
return(overflow); 
} 

Notice that the use of "%0" has potential conflicts with the my_mult function argument. Both the value of argument variable "a" and argument of __asm statement, the address of variable overflow, are passed in register $4. To avoid corrupting the value of argument "a" by the argument of the __asm statement, finish using the argument in $4 first, before using an __asm statement that contains arguments following its assembly string.

The inline assembler occasionally generates nop (no-operation) instructions to improve performance. Without the nop instructions, in some cases the processor would have to interlock the pipeline until all dependencies were satisfied. Insertion of the nop instructions changes the timing of instructions so that the pipeline hazard is avoided. The assembler automatically determines these situations for you.

Some assembly-language instructions are actually macros that result in the generation of more than one instruction. The sne instruction, which is used here, is an example of such a macro.

The last __asm statement, which takes the expression &overflow as an argument, generates an additional instruction that loads this expression into an argument register.

.text
.ent my_mult
.globl my_mult
# Begin code for function: my_mult
my_mult:
.set noreorder
    00000  fff8 27bd  addiu       sp,sp,0xFFF8
    00004                      .frame sp, 8, RA
    00004                      .mask 0x00000000, 0x00000000
    00004                      .fmask 0x00000000, 0x00000000
    00004                      .prologue 0
$M951:
    00004     1025 00c0        or          v0,a2,zero
    00008     0010 afa2        sw          v0,c$(sp)
    0000c     1025 00a0        or          v0,a1,zero
    00010     000c afa2        sw          v0,b$(sp)
    00014     1025 0080        or          v0,a0,zero
    00018     0008 afa2        sw          v0,a$(sp)
    0001c     0018 0085        mult        a0,a1      // $4 * $5; these are argument registers
    00020     2012 0000        mflo        a0         // $4 = lower 32 bits of result
    00024     1025 0080        or          v0,a0,zero // Store $r4 into *c 
    00028     0000 acc2        sw          v0,0(a2)   // Store $r4 into *c 
    0002c     5810 0000        mfhi        t3         // $11 = upper 32 bits of result
    00030     67c3 0004        sra         t4,a0,0x1F // Shift sign-bit into all lower bits
    00034     1023 018b        subu        v0,t4,t3   // sne (Set if Not-Equal)
    00038     0001 2c42        sltiu       v0,v0,1    // sne; overflow if the upper 32 bits
    0003c     0001 2403        addiu       v1,zero,1  // sne; are not the same as bit-31.
    00040     6023 0062        subu        t4,v1,v0   // sne 
    00044     0000 27a4        addiu       a0,sp,overflow$  // overflow = t4
    00048     0000 ac8c        sw          t4,0(a0)         // overflow = t4
    0004c     0000 8fa2        lw          v0,overflow$(sp) // return overflow;
    00050     0004 afa2        sw          v0,$T950(sp)     // return overflow;
    00054     0004 8fa2        lw          v0,$T950(sp)     // return overflow;
    00058     0008 27bd        addiu       sp,sp,8
    0005c     0008 03e0        jr          ra
    00060     0000 0000        nop
$M952:
.end
# End code for function: my_mult

See Also

MIPS Device Inline Assembly Language | Intrinsic Functions and MIPS Inline Assembly | MIPS Assembly Language Resources | The _asm Keyword in MIPS Inline Assembly

 Last updated on Thursday, April 08, 2004

© 1992-2003 Microsoft Corporation. All rights reserved.