assemblyarm

SMMUL instruction in ARM Assembly


Refer to: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/CHDHGFEF.html

Writes the most significant signed 32 bits of the result in Rd.

SMMUL is meant to multiply to vairable together but I do not understand how it calculates the "most significant signed 32 bits of the result"

Thanks in advance


Solution

  • When you multiply 2 32-bit value you get a 64-bit value and you have to save the result in two registers since a register is 32-bit. However may be you are not interested in lowest 32-bit and only highest 32-bit.

    SMMUL instruction provides you that. First calculates 64-bit result then it may simply discard/truncate lower 32-bits or it can round them into higher 32-bits (SMMULR).

    SMULL Rdlo, Rdhi, src1, src2 produces both halves in two output registers. (docs). Most Cortex-M microcontrollers either have both smmul and smull, or neither depending on whether they have a 64-bit multiplier. Cortex-M3 has smull (Thumb-2 group) but not smmul (DSP group).

    If you only need the high half, SMMUL avoids overwriting a second output register, and has the rounding version.

    $ cat smmul.c 
    int smull(int a, int b, int c, int d) {
        asm volatile("smmul r0, r2, r3");
      // only works in debug builds.  Use Extended Asm for real uses
    }
    
    int main() {
        int a, b, c;
        a = 0x00000001;
        b = 0x00000001;
        c = smull(0, 0, a, b);
        printf("%x(%d) %x(%d) %x(%d)\n", a, a, b, b, c, c);
        a = 0x40000000;
        b = 0x00000004;
        c = smull(0, 0, a, b);
        printf("%x(%d) %x(%d) %x(%d)\n", a, a, b, b, c, c); 
        return 0;
    }
    
    $ smmul
    1(1) 1(1) 0(0)
    40000000(1073741824) 4(4) 1(1)
    

    A less hacky version of the inline asm that actually tells the compiler what's going on:

    // untested, otherwise I'd edit the original test case.
    int smull(int a, int b, int c, int d)
    {
       // b is unused, kept only to match the original
        int retval;
        asm("smmul %0, %1, %2"
          : "=r"(retval)
          : "r"(c), "r"(d)
          : // no clobbers
        );
        return retval;
    }