
/*******************************************************************************
*
* File blk_smap.c
*
* Copyright (C) 2005 Martin Luescher
*
* This software is distributed under the terms of the GNU General Public
* License (GPL)
*
* Copying of the spinor fields to and from the blocks in a block grid
*
* The externally accessible functions are
*
*   void assign_s2sb(block_t *b,ptset_t set,int k,int l)
*     Assigns the relevant part of the global single-precision spinor field
*     ps[k][] to the single-precision field b.s[l] on the block b. Depending
*     on specified point set, the spinors on the even, odd or all points are
*     copied
*
*   void assign_sb2s(block_t *b,ptset_t set,int k,int l)
*     Assigns the single-precision spinor field b.s[k] on the block b to
*     the relevant part of the global single-precision field ps[l][].
*     Depending on specified point set, the spinors on the even, odd or all
*     points are copied
*
*   void assign_sd2sdb(block_t *b,ptset_t set,int k,int l)
*     Assigns the relevant part of the global double-precision spinor field
*     psd[k][] to the double-precision field b.sd[l] on the block b. Depending
*     on specified point set, the spinors on the even, odd or all points are
*     copied
*
*   void assign_sdb2sd(block_t *b,ptset_t set,int k,int l)
*     Assigns the double-precision spinor field b.sd[k] on the block b to
*     the relevant part of the global double-precision field psd[l][].
*     Depending on specified point set, the spinors on the even, odd or all
*     points are copied
*
* Notes:
*
* Only the spinors residing on the blocks (but not those on the boundaries)
* are copied
*
* These programs can be called locally, any errors being recorded by the
* error_loc [utils.c] function
*
*******************************************************************************/

#define BLK_SMAP_C

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "mpi.h"
#include "start.h"
#include "block.h"
#include "global.h"

static const spinor s0={{{0.0f}}};
static const spinor_dble sd0={{{0.0}}};

#if (defined SSE)
#include "sse.h"

void assign_s2sb(block_t *b,ptset_t set,int k,int l)
{
   int is,ns,*imb;
   spinor *rsb,*rsm,*rk,*rsk,*rsn;

   if (error_loc((k<0)||(k>=no_s)||(l<0)||(l>=(*b).ns),1,
                 "assign_s2sb [blk_smap.c]",
                 "Attempt to access unallocated memory space")!=0)
      return;

   is=0;
   ns=0;

   if (set==ALL_PTS)
      ns=(*b).vol;
   else if (set==EVEN_PTS)
      ns=(*b).volh;
   else if (set==ODD_PTS)
   {
      is=(*b).volh;
      ns=(*b).volh;
   }
   
   rsb=(*b).s[l]+is;
   rsm=rsb+ns;

   imb=(*b).imb+is;
   rk=ps[k][0];
   rsk=rk+(*imb);
   imb+=(rsb<(rsm-1));
   rsn=rk+(*imb);
   
   for (;rsb<rsm;rsb++)
   {
      __asm__ __volatile__ ("movaps %0, %%xmm0 \n\t"
                            "movaps %1, %%xmm1 \n\t"
                            "movaps %2, %%xmm2 \n\t"
                            "movaps %3, %%xmm3 \n\t"
                            "movaps %4, %%xmm4 \n\t"
                            "movaps %5, %%xmm5"
                            :
                            :
                            "m" ((*rsk).c1.c1),
                            "m" ((*rsk).c1.c3),
                            "m" ((*rsk).c2.c2),
                            "m" ((*rsk).c3.c1),
                            "m" ((*rsk).c3.c3),
                            "m" ((*rsk).c4.c2)
                            :
                            "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5");

      rsk=rsn;
      imb+=(rsb<(rsm-2));
      rsn=rk+(*imb);
      _prefetch_spinor(rsn);
      
      __asm__ __volatile__ ("movaps %%xmm0, %0 \n\t"
                            "movaps %%xmm1, %1 \n\t"
                            "movaps %%xmm2, %2 \n\t"
                            "movaps %%xmm3, %3 \n\t"
                            "movaps %%xmm4, %4 \n\t"
                            "movaps %%xmm5, %5"
                            :
                            "=m" ((*rsb).c1.c1),
                            "=m" ((*rsb).c1.c3),
                            "=m" ((*rsb).c2.c2),
                            "=m" ((*rsb).c3.c1),
                            "=m" ((*rsb).c3.c3),
                            "=m" ((*rsb).c4.c2));
   }
}



void assign_s2sb_ptr(block_t *b,ptset_t set,spinor *psk,int l)
{
   int is,ns,*imb;
   spinor *rsb,*rsm,*rk,*rsk,*rsn;

   is=0;
   ns=0;

   if (set==ALL_PTS)
      ns=(*b).vol;
   else if (set==EVEN_PTS)
      ns=(*b).volh;
   else if (set==ODD_PTS)
   {
      is=(*b).volh;
      ns=(*b).volh;
   }
   
   rsb=(*b).s[l]+is;
   rsm=rsb+ns;

   imb=(*b).imb+is;
   rk=psk;
   rsk=rk+(*imb);
   imb+=(rsb<(rsm-1));
   rsn=rk+(*imb);
   
   for (;rsb<rsm;rsb++)
   {
      __asm__ __volatile__ ("movaps %0, %%xmm0 \n\t"
                            "movaps %1, %%xmm1 \n\t"
                            "movaps %2, %%xmm2 \n\t"
                            "movaps %3, %%xmm3 \n\t"
                            "movaps %4, %%xmm4 \n\t"
                            "movaps %5, %%xmm5"
                            :
                            :
                            "m" ((*rsk).c1.c1),
                            "m" ((*rsk).c1.c3),
                            "m" ((*rsk).c2.c2),
                            "m" ((*rsk).c3.c1),
                            "m" ((*rsk).c3.c3),
                            "m" ((*rsk).c4.c2)
                            :
                            "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5");

      rsk=rsn;
      imb+=(rsb<(rsm-2));
      rsn=rk+(*imb);
      _prefetch_spinor(rsn);
      
      __asm__ __volatile__ ("movaps %%xmm0, %0 \n\t"
                            "movaps %%xmm1, %1 \n\t"
                            "movaps %%xmm2, %2 \n\t"
                            "movaps %%xmm3, %3 \n\t"
                            "movaps %%xmm4, %4 \n\t"
                            "movaps %%xmm5, %5"
                            :
                            "=m" ((*rsb).c1.c1),
                            "=m" ((*rsb).c1.c3),
                            "=m" ((*rsb).c2.c2),
                            "=m" ((*rsb).c3.c1),
                            "=m" ((*rsb).c3.c3),
                            "=m" ((*rsb).c4.c2));
   }
}


void assign_sb2s(block_t *b,ptset_t set,int k,int l)
{
   int is,ns,*imb;
   spinor *rsb,*rsm,*rl,*rsl;

   if (error_loc((k<0)||(k>=(*b).ns)||(l<0)||(l>=no_s),1,
       "assign_sb2s [blk_smap.c]",
       "Attempt to access unallocated memory space")!=0)
      return;

   is=0;
   ns=0;

   if (set==ALL_PTS)
      ns=(*b).vol;
   else if (set==EVEN_PTS)
      ns=(*b).volh;
   else if (set==ODD_PTS)
   {
      is=(*b).volh;
      ns=(*b).volh;
   }

   rsb=(*b).s[k]+is;
   rsm=rsb+ns;
   
   imb=(*b).imb+is;
   rl=ps[l][0];

   for (;rsb<rsm;)
   {
      __asm__ __volatile__ ("movaps %0, %%xmm0 \n\t"
                            "movaps %1, %%xmm1 \n\t"
                            "movaps %2, %%xmm2 \n\t"
                            "movaps %3, %%xmm3 \n\t"
                            "movaps %4, %%xmm4 \n\t"
                            "movaps %5, %%xmm5"
                            :
                            :
                            "m" ((*rsb).c1.c1),
                            "m" ((*rsb).c1.c3),
                            "m" ((*rsb).c2.c2),
                            "m" ((*rsb).c3.c1),
                            "m" ((*rsb).c3.c3),
                            "m" ((*rsb).c4.c2)
                            :
                            "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5");

      rsb+=4;
      _prefetch_spinor(rsb);
      rsb-=3;
      
      rsl=rl+(*imb);
      imb+=1;      
      
      __asm__ __volatile__ ("movaps %%xmm0, %0 \n\t"
                            "movaps %%xmm1, %1 \n\t"
                            "movaps %%xmm2, %2 \n\t"
                            "movaps %%xmm3, %3 \n\t"
                            "movaps %%xmm4, %4 \n\t"
                            "movaps %%xmm5, %5"
                            :
                            "=m" ((*rsl).c1.c1),
                            "=m" ((*rsl).c1.c3),
                            "=m" ((*rsl).c2.c2),
                            "=m" ((*rsl).c3.c1),
                            "=m" ((*rsl).c3.c3),
                            "=m" ((*rsl).c4.c2));
   }
}

#else

void assign_s2sb_ptr(block_t *b,ptset_t set,spinor *psk,int l)
{
   int is,ns,*imb;
   spinor *rk,*rsb,*rsm;


   is=0;
   ns=0;

   if (set==ALL_PTS)
      ns=(*b).vol;
   else if (set==EVEN_PTS)
      ns=(*b).volh;
   else if (set==ODD_PTS)
   {
      is=(*b).volh;
      ns=(*b).volh;
   }

   imb=(*b).imb+is;
   rk=psk;
   rsb=(*b).s[l]+is;
   rsm=rsb+ns;

   for (;rsb<rsm;rsb++)
   {
      *rsb=*(rk+(*imb));
      imb+=1;
   }
}

void assign_s2sb(block_t *b,ptset_t set,int k,int l)
{
   int is,ns,*imb;
   spinor *rk,*rsb,*rsm;

   if (error_loc((k<0)||(k>=no_s)||(l<0)||(l>=(*b).ns),1,
       "assign_s2sb [blk_smap.c]",
       "Attempt to access unallocated memory space")!=0)
      return;

   is=0;
   ns=0;

   if (set==ALL_PTS)
      ns=(*b).vol;
   else if (set==EVEN_PTS)
      ns=(*b).volh;
   else if (set==ODD_PTS)
   {
      is=(*b).volh;
      ns=(*b).volh;
   }

   imb=(*b).imb+is;
   rk=ps[k][0];
   rsb=(*b).s[l]+is;
   rsm=rsb+ns;

   for (;rsb<rsm;rsb++)
   {
      *rsb=*(rk+(*imb));
      imb+=1;
   }
}



void assign_sb2s(block_t *b,ptset_t set,int k,int l)
{
   int is,ns,*imb;
   spinor *rl,*rsb,*rsm;

   if (error_loc((k<0)||(k>=(*b).ns)||(l<0)||(l>=no_s),1,
       "assign_sb2s [blk_smap.c]",
       "Attempt to access unallocated memory space")!=0)
      return;

   is=0;
   ns=0;

   if (set==ALL_PTS)
      ns=(*b).vol;
   else if (set==EVEN_PTS)
      ns=(*b).volh;
   else if (set==ODD_PTS)
   {
      is=(*b).volh;
      ns=(*b).volh;
   }

   imb=(*b).imb+is;
   rl=ps[l][0];
   rsb=(*b).s[k]+is;
   rsm=rsb+ns;

   for (;rsb<rsm;rsb++)
   {
      *(rl+(*imb))=*rsb;
      imb+=1;
   }
}

#endif


void assign_sd2sdb(block_t *b,ptset_t set,int k,int l)
{
   int is,ns,*imb;
   spinor_dble *rk,*rsb,*rsm;

   if (error_loc((k<0)||(k>=no_sd)||(l<0)||(l>=(*b).nsd),1,
       "assign_sd2sdb [blk_smap.c]",
       "Attempt to access unallocated memory space")!=0)
      return;

   is=0;
   ns=0;

   if (set==ALL_PTS)
      ns=(*b).vol;
   else if (set==EVEN_PTS)
      ns=(*b).volh;
   else if (set==ODD_PTS)
   {
      is=(*b).volh;
      ns=(*b).volh;
   }

   imb=(*b).imb+is;
   rk=psd[k][0];
   rsb=(*b).sd[l]+is;
   rsm=rsb+ns;

   for (;rsb<rsm;rsb++)
   {
      *rsb=*(rk+(*imb));
      imb+=1;
   }
}


void assign_sdb2sd(block_t *b,ptset_t set,int k,int l)
{
   int is,ns,*imb;
   spinor_dble *rl,*rsb,*rsm;

   if (error_loc((k<0)||(k>=(*b).nsd)||(l<0)||(l>=no_sd),1,
       "assign_sdb2sd [blk_smap.c]",
       "Attempt to access unallocated memory space")!=0)
      return;

   is=0;
   ns=0;

   if (set==ALL_PTS)
      ns=(*b).vol;
   else if (set==EVEN_PTS)
      ns=(*b).volh;
   else if (set==ODD_PTS)
   {
      is=(*b).volh;
      ns=(*b).volh;
   }

   imb=(*b).imb+is;
   rl=psd[l][0];
   rsb=(*b).sd[k]+is;
   rsm=rsb+ns;

   for (;rsb<rsm;rsb++)
   {
      *(rl+(*imb))=*rsb;
      imb+=1;
   }
}
