title: cmm call format for foreign primop (integer-gmp example)
body: <p>I have been checking out <a href="https://github.com/ghc/packages-integer-gmp">integer-gmp</a> source code to understand how foreign primops can be implemented in terms of cmm as documented on <a href="http://hackage.haskell.org/trac/ghc/wiki/Commentary/PrimOps">GHC Primops page</a>. I am aware of techniques to implement them using <a href="http://breaks.for.alienz.org/blog/2012/02/09/parsing-market-data-feeds-with-ragel/">llvm hack</a> or fvia-C/gcc - this is more of a learning experience for me to understand this third approach that interger-gmp library uses.</p>
  
  <p>So, I looked up CMM tutorial on MSFT page <a href="http://www.cminusminus.org/extern/man2.pdf">(pdf link)</a>, went through <a href="http://hackage.haskell.org/trac/ghc/wiki/Commentary/Compiler/CmmType">GHC CMM page</a>, and still there are some unanswered questions (hard to keep all those concepts in head without digging into CMM which is what I am doing now). There is this code fragment from <a href="https://github.com/ghc/packages-integer-gmp/blob/master/cbits/gmp-wrappers.cmm">integer-bmp cmm file</a>:</p>
  
  <pre><code>integer_cmm_int2Integerzh (W_ val)
  {
     W_ s, p; /* to avoid aliasing */
  
     ALLOC_PRIM_N (SIZEOF_StgArrWords + WDS(1), integer_cmm_int2Integerzh, val);
  
     p = Hp - SIZEOF_StgArrWords;
     SET_HDR(p, stg_ARR_WORDS_info, CCCS);
     StgArrWords_bytes(p) = SIZEOF_W;
  
     /* mpz_set_si is inlined here, makes things simpler */
     if (%lt(val,0)) {
          s  = -1;
          Hp(0) = -val;
     } else {
       if (%gt(val,0)) {
          s = 1;
          Hp(0) = val;
       } else {
          s = 0;
       }
    }
  
     /* returns (# size  :: Int#,
                   data  :: ByteArray#
                 #)
     */
     return (s,p);
  }
  </code></pre>
  
  <p>As defined in <a href="https://github.com/ghc/ghc/blob/master/includes/Cmm.h">ghc cmm header</a>:</p>
  
  <pre><code>W_ is alias for word.
  ALLOC_PRIM_N is a function for allocating memory on the heap for primitive object.
  Sp(n) and Hp(n) are defined as below (comments are mine):
  #define WDS(n) ((n)*SIZEOF_W) //WDS(n) calculates n*sizeof(Word)
  #define Sp(n)  W_[Sp + WDS(n)]//Sp(n) points to Stackpointer + n word offset?
  #define Hp(n)  W_[Hp + WDS(n)]//Hp(n) points to Heap pointer + n word offset?
  </code></pre>
  
  <p>I don't understand lines 5-9 (line 1 is the start in case you have 1/0 confusion). More specifically:</p>
  
  <ul>
  <li>Why is the function call format of ALLOC_PRIM_N (bytes,fun,arg) that way?</li>
  <li>Why is p manipulated that way?</li>
  </ul>
  
  <p>The function as I understand it (from looking at function signature in <a href="https://github.com/ghc/packages-integer-gmp/blob/master/GHC/Integer/GMP/Prim.hs">Prim.hs</a>) takes an int, and returns a (int, byte array) (stored in <code>s</code>,<code>p</code> respectively in the code).  </p>
  
  <p>For anyone who is wondering about inline call in <code>if block</code>, it is cmm implementation of gmp <a href="http://stuff.mit.edu/afs/sipb.mit.edu/project/stk/src/STk-2.2.0/Mp/gmp-1.3.2/mpz_set_si.c">mpz_init_si function</a>. My guess is if you call a function defined in object file through ccall, it can't be inlined (which makes sense since it is object-code, not intermediate code - LLVM approach seems more suitable for inlining through LLVM IR). So, the optimization was to define a cmm representation of the function to be inlined. Please correct me if this guess is wrong.</p>
  
  <p>Explanation of lines 5-9 will be very much appreciated. I have more questions about other macros defined in integer-gmp file, but it might be too much to ask in one post. If you can answer the question with a Haskell wiki page or a blog (you can post the link as answer), that would be much appreciated (and if you do, I would also appreciate step-by-step walk-through of an integer-gmp cmm macro such as <code>GMP_TAKE2_RET1</code>).</p>