title: GCC inline assembly for SPARC: How to handle integer doubleword pairs?
body: <p>From what I understand, in SPARC, 32-bit integer quantities are stored in single registers and 64-bit integer quantities are stored in adjacent register pairs, with the even register containing the high 32 bits and the odd register containing the low 32 bits.</p>
  
  <p>I need to write a few specialized SPARC inline assembly macros (inline assembly functions would be fine too) that deal with 64-bit integer doubleword pairs, and I can't figure out how to refer generically (using GCC extended inline assembly) to the two halves of the pair in my inline assembly.  Though my assembly macros will be a little more complex than the MULTIPLY() macro shown below, the multiplication example, if it worked, would demonstrate how to deal with the two halves of a 64-bit doubleword pair.  Can anyone tell me how to fix my MULTIPLY() macro?</p>
  
  <p>In case it matters, I'm on a...</p>
  
  <blockquote>
    <p>bash-2.03$ uname -a<br>
    SunOS [...] 5.8 Generic_117350-39 sun4u sparc SUNW,Ultra-80</p>
  </blockquote>
  
  <p>Here is my trivial example program (in C):</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  //#include &lt;stdint.h&gt;
  #define uint32 unsigned long int
  #define uint64 unsigned long long int
  
  
  #define MULTIPLY(r, a, b)  /* (r = a * b) */   \
     asm("umul %1, %2, %0;"  /* unsigned mul */  \
         : /* regs out */  "=h"(r)               \
         : /* regs in  */  "r"(a),   "r"(b));
  #if 0
         : /* clobbers */  "%y" );
  #endif
  
  
  int main(int argc, char** argv)
  {
     uint64 r;
     uint32 a=0xdeadbeef, b=0xc0deba5e;
  
     // loses the top 32 bits of the multiplication because the result is
     // truncated at 32 bits which then gets assigned to the 64-bit 'r'...
     r = a * b;
     printf("u64=u32*u32  ----&gt;  r=a*b           "
            "----&gt;  0x%016llx = 0x%x * 0x%x\n",
            r, a, b);
  
     // force promotion of 'a' to uint64 to get 64-bit multiplication
     // (could cast either a or b as uint64, which one doesn't matter,
     // as one explicit cast causes the other to be promoted as well)...
     r = ((uint64)a) * b;
     printf("u64=u64*u32  ----&gt;  r=((u64)a)*b    "
            "----&gt;  0x%016llx = 0x%x * 0x%x\n",
            r, a, b);
  
     MULTIPLY(r, a, b);
     printf("u64=u64*u32  ----&gt;  MULTIPLY(r,a,b) "
            "----&gt;  0x%016llx = 0x%x * 0x%x\n",
            r, a, b);
  
     return 0;
  }
  </code></pre>
  
  <p>Which, when compiled with <code>gcc-3.2-sun4u/bin/gcc -o mult -mcpu=ultrasparc mult.c</code>, produces this output:</p>
  
  <pre><code>u64=u32*u32  ----&gt;  r=a*b           ----&gt;  0x00000000d3c7c1c2 = 0xdeadbeef * 0xc0deba5e  
  u64=u64*u32  ----&gt;  r=((u64)a)*b    ----&gt;  0xa7c40bfad3c7c1c2 = 0xdeadbeef * 0xc0deba5e  
  u64=u64*u32  ----&gt;  MULTIPLY(r,a,b) ----&gt;  0xd3c7c1c2deadbeef = 0xdeadbeef * 0xc0deba5e  
  </code></pre>
  
  <p>I looked at the <code>-S -fverbose-asm</code> output of gcc, and it's doing some strange shifting of the result register (which is even) &amp; writing into the adjacent odd register.  My problem is that I don't know how to generically refer to the adjacent odd register in the extended asm syntax.  I thought perhaps the 'h' asm constraint in <code>"=h"(r)</code> might have something to do with it, but I can't find any examples of how to use it.</p>