!===============================================================================
!
! cg_clover_mult_a2_simd.F90
!
!-------------------------------------------------------------------------------
!
! Copyright (C) 2012-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/>.
!
!-------------------------------------------------------------------------------
# define LANGUAGE_FORTRAN
# define SIMD
# include "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_c2)
!-------------------------------------------------------------------------------
subroutine Tclover(cg_c2)(out, b, a, in, volh_tot, varsBLOCK)  ! out := b out + A in

  use module_simd
  use typedef_cg_clover
  implicit none
  integer, intent(in) :: varsBLOCK
  integer, intent(in) :: volh_tot

  spincol_FIELD, intent(inout) :: out
  spincol_FIELD, intent(in) :: in
  clover_FLD, intent(in) :: a
  REAL, intent(in) :: b

  SIMD_VECTOR :: PRIVATE_VARS_01
  SIMD_VECTOR :: PRIVATE_VARS_02
  SIMD_VECTOR :: PRIVATE_VARS_03
  SIMD_VECTOR :: PRIVATE_VARS_04
  SIMD_VECTOR :: bvec
  
  integer :: ii

  TRACE_ENTRY
  TIMING_START(timing_bin_cg_clover_mult_a2)

  bvec = LoadS(b)

#ifndef BLOCK
  !$omp parallel do default(none) &
  !$omp shared(volh, out, b, a, in, bvec) &
  !$omp private(PRIVATE_VARS_01) &
  !$omp private(PRIVATE_VARS_02) &
  !$omp private(PRIVATE_VARS_03) &
  !$omp private(PRIVATE_VARS_04) 
  do ii = 1, varsBLOCK
#else
  do ii = varsBLOCK
#endif

DO block = 1, 2
! _block_ = block
SET ADD = $(ifthenelse '((block==1))' Add Sub) 
DO colour = 1, 3
DO spin = 1, 2
LET j = (spin-1)*3 + colour
! _j_ j
re_x%%j = ADD(Load(Real(Spincol(in, spin, 1, colour, ii))), Load(Real(Spincol(in, spin, 2, colour, ii))))
im_x%%j = ADD(Load(Imag(Spincol(in, spin, 1, colour, ii))), Load(Imag(Spincol(in, spin, 2, colour, ii))))

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 ))
Store(Real(Spincol(out, spin, 1, colour, ii)), Fmadd(Load(Real(Spincol(out, spin, 1, colour, ii))), bvec, re_y%%j))
Store(Imag(Spincol(out, spin, 1, colour, ii)), Fmadd(Load(Imag(Spincol(out, spin, 1, colour, ii))), bvec, im_y%%j))
Store(Real(Spincol(out, spin, 2, colour, ii)), Fmadd(Load(Real(Spincol(out, spin, 2, colour, ii))), bvec, re_y%%j))
Store(Imag(Spincol(out, spin, 2, colour, ii)), Fmadd(Load(Imag(Spincol(out, spin, 2, colour, ii))), bvec, im_y%%j))
ELSE
Store(Real(Spincol(out, spin, 1, colour, ii)), Add(Load(Real(Spincol(out, spin, 1, colour, ii))), re_y%%j))
Store(Imag(Spincol(out, spin, 1, colour, ii)), Add(Load(Imag(Spincol(out, spin, 1, colour, ii))), im_y%%j))
Store(Real(Spincol(out, spin, 2, colour, ii)), Sub(Load(Real(Spincol(out, spin, 2, colour, ii))), re_y%%j))
Store(Imag(Spincol(out, spin, 2, colour, ii)), Sub(Load(Imag(Spincol(out, spin, 2, colour, ii))), im_y%%j))
ENDIF

ENDLET
ENDDO
ENDDO

ENDSET
ENDDO

  enddo

  TIMING_STOP(timing_bin_cg_clover_mult_a2)
  TRACE_RETURN
end

!===============================================================================
