/*
!===============================================================================
!
! cg_clover_mult_ao_simd_.c
!
!-------------------------------------------------------------------------------
!
! Copyright (C) 2015-2017 Hinnerk Stueben
!
! This file is part of BQCD -- Berlin Quantum ChromoDynamics program
!
! BQCD is free software: you can redistribute it and/or modify
! it under the terms of the GNU General Public License as published by
! the Free Software Foundation, either version 3 of the License, or
! (at your option) any later version.
!
! BQCD is distributed in the hope that it will be useful,
! but WITHOUT ANY WARRANTY; without even the implied warranty of
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
! GNU General Public License for more details.
!
! You should have received a copy of the GNU General Public License
! along with BQCD.  If not, see <http://www.gnu.org/licenses/>.
!
!-------------------------------------------------------------------------------
*/
#ifndef LANGUAGE_C
# define LANGUAGE_C
#endif
# define SIMD
# include "c_defs.h"
# include "simd.h"
# include "alignment.h"
# include "cg_defs.h"
# include "cg_d.h"
# include "cg_clover.i"

//-------------------------------------------------------------------------------
# define PRIVATE_VARS_01 re_x1, re_x2, re_x3, re_x4, re_x5, re_x6
# define PRIVATE_VARS_02 im_x1, im_x2, im_x3, im_x4, im_x5, im_x6
# define PRIVATE_VARS_03 re_y1, re_y2, re_y3, re_y4, re_y5, re_y6
# define PRIVATE_VARS_04 im_y1, im_y2, im_y3, im_y4, im_y5, im_y6

//-------------------------------------------------------------------------------
# define TRACE_NAME Tclover(cg_co)
//-------------------------------------------------------------------------------
void Tclover(cg_co)(  // inout := A inout
    clover_FLD a,
    spincol_FLD inout,
    int *volh_tot,
#ifdef BLOCK
    int *i1, int *i2
#else
    int *volh
#endif
    )
{
    SIMD_VECTOR PRIVATE_VARS_01;
    SIMD_VECTOR PRIVATE_VARS_02;
    SIMD_VECTOR PRIVATE_VARS_03;
    SIMD_VECTOR PRIVATE_VARS_04;
  
    spincol_FLD inout1 = inout;
    spincol_FLD inout2 = inout + *volh_tot;

    int ii;

    TRACE_ENTRY;
    TIMING_START(timing_bin_cg_clover_mult_ao);

    inout--; inout1--; inout2--;
    a--;

#ifndef BLOCK
#pragma omp parallel for default(none)					\
    shared(volh, inout, inout1, inout2, a)				\
    private(PRIVATE_VARS_01)						\
    private(PRIVATE_VARS_02)						\
    private(PRIVATE_VARS_03)						\
    private(PRIVATE_VARS_04) 
    for (ii = 1; ii <= *volh; ii++)
#else
    for (ii = *i1; ii <= *i2; ii++)
#endif
    {
DO block = 1, 2
//_block_ = block
DO colour = 1, 3
DO spin = 1, 2
LET j = (spin-1)*3 + colour
//_j_ j
IF (( block == 1 ))
re_x%%j = Add(Load(Real(Spincol(inout, spin, 1, colour, ii))), Load(Real(Spincol(inout, spin, 2, colour, ii))));
im_x%%j = Add(Load(Imag(Spincol(inout, spin, 1, colour, ii))), Load(Imag(Spincol(inout, spin, 2, colour, ii))));
ENDIF

DO i = 1, j-1
IF (( j == 1 ))
re_y%%i =   Mul(Load(ImClover(a, block, ii, i, j)), im_x%%j);
im_y%%i =   Mul(Load(ImClover(a, block, ii, i, j)), re_x%%j);
ELSE
re_y%%i = Fmsub(Load(ImClover(a, block, ii, i, j)), im_x%%j, re_y%%i);
im_y%%i = Fmadd(Load(ImClover(a, block, ii, i, j)), re_x%%j, im_y%%i);
ENDIF
ENDDO
IF (( j == 1 ))
re_y%%j = LoadS(ZERO);
im_y%%j = LoadS(ZERO);
ELSE
//_y%%j
//_y%%j
ENDIF
DO i = j+1, 6
IF (( j == 1 ))
re_y%%i =   Mul(Load(ImClover(a, block, ii, j, i)), im_x%%j);
im_y%%i =   Mul(Load(ImClover(a, block, ii, j, i)), re_x%%j);
ELSE
re_y%%i = Fmadd(Load(ImClover(a, block, ii, j, i)), im_x%%j, re_y%%i);
im_y%%i = Fmsub(Load(ImClover(a, block, ii, j, i)), re_x%%j, im_y%%i);
ENDIF
ENDDO

DO i = 1, j-1
re_y%%i = Fmsub(Load(ReClover(a, block, ii, i, j)), re_x%%j, re_y%%i);
im_y%%i = Fmadd(Load(ReClover(a, block, ii, i, j)), im_x%%j, im_y%%i);
ENDDO
LET i = j
re_y%%i = Fmadd(Load(ReClover(a, block, ii, i, j)), re_x%%j, re_y%%j);
im_y%%i = Fmadd(Load(ReClover(a, block, ii, i, j)), im_x%%j, im_y%%j);
ENDLET
DO i = j+1, 6
re_y%%i = Fmadd(Load(ReClover(a, block, ii, j, i)), re_x%%j, re_y%%i);
im_y%%i = Fmsub(Load(ReClover(a, block, ii, j, i)), im_x%%j, im_y%%i);
ENDDO

ENDLET
ENDDO
ENDDO

DO colour = 1, 3
DO spin = 1, 2
LET j = (spin-1)*3 + colour
IF (( block == 1 ))
re_x%%j = Sub(Load(Real(Spincol(inout, spin, 1, colour, ii))), Load(Real(Spincol(inout, spin, 2, colour, ii))));
im_x%%j = Sub(Load(Imag(Spincol(inout, spin, 1, colour, ii))), Load(Imag(Spincol(inout, spin, 2, colour, ii))));
Store(Real(Spincol(inout, spin, 1, colour, ii)), re_y%%j);
Store(Imag(Spincol(inout, spin, 1, colour, ii)), im_y%%j);
Store(Real(Spincol(inout, spin, 2, colour, ii)), re_y%%j);
Store(Imag(Spincol(inout, spin, 2, colour, ii)), im_y%%j);
ELSE
Store(Real(Spincol(inout, spin, 1, colour, ii)), Add(Load(Real(Spincol(inout, spin, 1, colour, ii))), re_y%%j));
Store(Imag(Spincol(inout, spin, 1, colour, ii)), Add(Load(Imag(Spincol(inout, spin, 1, colour, ii))), im_y%%j));
Store(Real(Spincol(inout, spin, 2, colour, ii)), Sub(Load(Real(Spincol(inout, spin, 2, colour, ii))), re_y%%j));
Store(Imag(Spincol(inout, spin, 2, colour, ii)), Sub(Load(Imag(Spincol(inout, spin, 2, colour, ii))), im_y%%j));
ENDIF

ENDLET
ENDDO
ENDDO

ENDDO

    }

    TIMING_STOP(timing_bin_cg_clover_mult_ao);
    TRACE_RETURN;
}

//==============================================================================
