text: #include "atlas_misc.h"
  #include "atlas_threads.h"
  #include "atlas_tlvl3.h"
  /*
   * prototype the typeless tGEMM helper routines
   */
  void ATL_DoWorkMM(ATL_LAUNCHSTRUCT_t *lp, void *vp);
  int ATL_StructIsInitMM(void *vp);
  int ATL_thrdecompMM
     (ATL_TMMNODE_t *ptmms, const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB,
      ATL_CINT M, ATL_CINT N, ATL_CINT K, const void *A, ATL_INT lda,
      const void *B, const ATL_INT ldb, const void *C, ATL_CINT ldc, const int P,
      int *DivideK);
  
  void Mjoin(PATL,InitTMMNodes)
     (const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB, const TYPE *alpha,
      const TYPE *beta, const TYPE *one, const TYPE *zero,
      ATL_thread_t *btp, ATL_TMMNODE_t *ptmms);
  void Mjoin(PATL,HandleNewCp)(ATL_TMMNODE_t *me, ATL_TMMNODE_t *him);
  int Mjoin(PATL,CombineCw)(ATL_TMMNODE_t *me, ATL_TMMNODE_t *him);
  void Mjoin(PATL,CombineStructsMM)(void *vp, const int myrank, const int herank);
  int Mjoin(PATL,tgemm_p)(const enum ATLAS_TRANS TA, const enum ATLAS_TRANS TB,
                         ATL_CINT M, ATL_CINT N, ATL_CINT K, const SCALAR alpha,
                         const TYPE *A, ATL_CINT lda, const TYPE *B, ATL_CINT ldb,
                         const SCALAR beta, TYPE *C, ATL_CINT ldc)
  {
     #ifdef ATL_SERIAL_COMBINE
        ATL_combnode_t *combb=NULL, *combp;
     #endif
     ATL_TMMNODE_t mms[ATL_NTHREADS];
     int i, np, DividedK=0;
     #ifdef TREAL
        TYPE ONE=ATL_rone, ZERO=ATL_rzero;
     #else
        TYPE ONE[2] = {ATL_rone, ATL_rzero}, ZERO[2] = {ATL_rzero, ATL_rzero};
     #endif
     extern int ATL_FINDP;
  
     if (M < 1 || N < 1)
        return(0);
     if (K < 1 || SCALAR_IS_ZERO(alpha))
     {
        if (!SCALAR_IS_ONE(beta))
           Mjoin(PATL,gescal)(M, N, beta, C, ldc);
        return(0);
     }
     Mjoin(PATL,InitTMMNodes)(TA, TB, SADD alpha, SADD beta, SADD ONE,
                              SADD ZERO, NULL, mms);
     np = ATL_thrdecompMM(mms, TA, TB, M, N, K, A, lda, B, ldb, C, ldc,
                          ATL_FINDP, &DividedK);
     if (np < ATL_FINDP)
        return(0);
  #ifdef DEBUG
  fprintf(stderr, "np=%d\n\n", np);
  #endif
     if (np < 2)
     {
        Mjoin(PATL,gemm)(TA, TB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);
        return(1);
     }
  /*
   * If we are debugging, set up serial combine queue
   */
     #ifdef ATL_SERIAL_COMBINE
        for (i=0; i < ATL_NTHREADS; i++)
        {
           if (mms[i].K)   /* if this struct being used */
           {
              if (!mms[i].ownC)   /* I need a workspace for C */
              {
                 mms[i].Cw = calloc(mms[i].ldcw * mms[i].N, ATL_sizeof);
                 ATL_assert(mms[i].Cw);
                 combb = ATL_NewCombnode(mms[i].M, mms[i].N, mms[i].Cw,
                                         mms[i].ldcw, mms[i].C, mms[i].ldc,
                                         combb);
              }
           }
        }
     #endif
  
     ATL_goparallel(np, ATL_DoWorkMM, mms,
                    DividedK ? Mjoin(PATL,CombineStructsMM) : NULL);
  /*
   * If we are debugging, serially combine all workspaces back to original C
   */
     #ifdef ATL_SERIAL_COMBINE
        while(combb)
        {
           Mjoin(PATL,geadd)(combb->M, combb->N, ONE, combb->W, combb->ldw,
                             ONE, combb->D, combb->ldd);
           free(combb->W);
           combp = combb;
           combb = combb->next;
           free(combp);
        }
     #endif
     return(np);
  }
  