#===============================================================================
#
# cg_d_x.sh - generates special source code for x-direction of d-slash
#
#-------------------------------------------------------------------------------
#
# Copyright (C) 2015-2016 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/>.
#
#------------------------------------------------------------------------------
function Declarations_x
{
    if ((!simd)); then return; fi

    if [[ $mu != x ]]; then return; fi

    Integer abs_jf, abs_jb

    case $lang in
        Fortran)
            Echo 'REAL, dimension(SIMD_WIDTH) :: mask1110, mask0001, mask0111, mask1000'
            ;;
    esac
}

#------------------------------------------------------------------------------
function InitJ_x  # Usage: InitJ_x {bwd|fwd}
{
    if ((!simd)); then return; fi
    if [[ $mu != x ]]; then return; fi

    case $1 in
        bwd) Echo "abs_jb = $(Abs $j_bwd);" ;;
        fwd) Echo "abs_jf = $(Abs $j_fwd);" ;;
    esac
}

#------------------------------------------------------------------------------
function InitMask_x
{
    if ((!simd)); then return; fi

    if [[ $mu != x ]]; then return; fi

    case $lang in
        Fortran)
            Echo 'mask1110(:) = ONE;  mask1110(SIMD_WIDTH) = ZERO'
            Echo 'mask0001(:) = ZERO; mask0001(SIMD_WIDTH) = ONE'
            Echo 'mask0111(:) = ONE;  mask0111(1) = ZERO'
            Echo 'mask1000(:) = ZERO; mask1000(1) = ONE'
            ;;
    esac 
}

#------------------------------------------------------------------------------
function OpenMpDeclarations_x
{
    if ((!simd)); then return; fi
    if [[ $mu != x ]]; then return; fi

    Echo "$omp private(abs_jf, abs_jb) $continuation_mark"
    Echo "$omp shared(mask0001, mask0111, mask1000, mask1110) $continuation_mark"
}

#------------------------------------------------------------------------------
function ProjectionD2_x
{
    if (( ! simd ));   then Die "ProjectionD2_x: need simd"; fi
    if [[ $mu != x ]]; then Die "ProjectionD2_x: need mu=x"; fi

    typeset j j1 j2 abs_j shift1 shift2 mask1 mask2 Shift1 Shift2

    typeset FMADD="Fm$(ToLower $ADD)"
    typeset FMSUB="Fm$(ToLower $SUB)"

    eval "j=\$j_$dir"
    abs_j=abs_$j

    case $dir in
        fwd) j1=i;      j2=$abs_j; shift1=1;  shift2=1-SIMD_WIDTH; mask1=mask1110; mask2=mask0001;;
        bwd) j1=$abs_j; j2=i;      shift1=SIMD_WIDTH-1; shift2=-1; mask1=mask1000; mask2=mask0111;;
    esac 

    case $lang in
        C)
            Shift1="[$shift1]"; Shift2="[$shift2]";;
        Fortran)
            Shift1="($shift1+1:$shift1+SIMD_WIDTH)"; Shift2="($shift2+1:$shift2+SIMD_WIDTH)";;
    esac
    
    If "($j == i)"

    Echo "re_A1_$dir = $ADD(Load(reINPUT_$dir(1,1,$k,i)), Load(imINPUT_$dir(2,2,$k,i)));"
    Echo "im_A1_$dir = $SUB(Load(imINPUT_$dir(1,1,$k,i)), Load(reINPUT_$dir(2,2,$k,i)));"
    Echo "re_A2_$dir = $ADD(Load(reINPUT_$dir(2,1,$k,i)), Load(imINPUT_$dir(1,2,$k,i)));"
    Echo "im_A2_$dir = $SUB(Load(imINPUT_$dir(2,1,$k,i)), Load(reINPUT_$dir(1,2,$k,i)));"

    Else

    case $simdkind in
        ibm)
            Echo "re_A1_$dir = ShiftLeft2(Load(reINPUT_$dir(1,1,$k,$j1)), Load(reINPUT_$dir(1,1,$k,$j2)), $shift1);"
            Echo "im_A1_$dir = ShiftLeft2(Load(imINPUT_$dir(1,1,$k,$j1)), Load(imINPUT_$dir(1,1,$k,$j2)), $shift1);"
            Echo "re_A2_$dir = ShiftLeft2(Load(reINPUT_$dir(2,1,$k,$j1)), Load(reINPUT_$dir(2,1,$k,$j2)), $shift1);"
            Echo "im_A2_$dir = ShiftLeft2(Load(imINPUT_$dir(2,1,$k,$j1)), Load(imINPUT_$dir(2,1,$k,$j2)), $shift1);"

            Echo "re_A1_$dir = $ADD(re_A1_$dir, ShiftLeft2(Load(imINPUT_$dir(2,2,$k,$j1)), Load(imINPUT_$dir(2,2,$k,$j2)), $shift1));"
            Echo "im_A1_$dir = $SUB(im_A1_$dir, ShiftLeft2(Load(reINPUT_$dir(2,2,$k,$j1)), Load(reINPUT_$dir(2,2,$k,$j2)), $shift1));"
            Echo "re_A2_$dir = $ADD(re_A2_$dir, ShiftLeft2(Load(imINPUT_$dir(1,2,$k,$j1)), Load(imINPUT_$dir(1,2,$k,$j2)), $shift1));"
            Echo "im_A2_$dir = $SUB(im_A2_$dir, ShiftLeft2(Load(reINPUT_$dir(1,2,$k,$j1)), Load(reINPUT_$dir(1,2,$k,$j2)), $shift1));"
            ;;
        intel)
            Echo "re_A1_$dir =    Mul(LoadU(imINPUT_$dir(2,2,$k,$j1)$Shift1), Load($mask1));"
            Echo "im_A1_$dir =    Mul(LoadU(reINPUT_$dir(2,2,$k,$j1)$Shift1), Load($mask1));"
            Echo "re_A2_$dir =    Mul(LoadU(imINPUT_$dir(1,2,$k,$j1)$Shift1), Load($mask1));"
            Echo "im_A2_$dir =    Mul(LoadU(reINPUT_$dir(1,2,$k,$j1)$Shift1), Load($mask1));"

            Echo "re_A1_$dir =  Fmadd(LoadU(imINPUT_$dir(2,2,$k,$j2)$Shift2), Load($mask2), re_A1_$dir);"
            Echo "im_A1_$dir =  Fmadd(LoadU(reINPUT_$dir(2,2,$k,$j2)$Shift2), Load($mask2), im_A1_$dir);"
            Echo "re_A2_$dir =  Fmadd(LoadU(imINPUT_$dir(1,2,$k,$j2)$Shift2), Load($mask2), re_A2_$dir);"
            Echo "im_A2_$dir =  Fmadd(LoadU(reINPUT_$dir(1,2,$k,$j2)$Shift2), Load($mask2), im_A2_$dir);"

            Echo "re_A1_$dir = $FMADD(LoadU(reINPUT_$dir(1,1,$k,$j1)$Shift1), Load($mask1), re_A1_$dir);"
            Echo "im_A1_$dir = $FMSUB(LoadU(imINPUT_$dir(1,1,$k,$j1)$Shift1), Load($mask1), im_A1_$dir);"
            Echo "re_A2_$dir = $FMADD(LoadU(reINPUT_$dir(2,1,$k,$j1)$Shift1), Load($mask1), re_A2_$dir);"
            Echo "im_A2_$dir = $FMSUB(LoadU(imINPUT_$dir(2,1,$k,$j1)$Shift1), Load($mask1), im_A2_$dir);"

            Echo "re_A1_$dir =  Fmadd(LoadU(reINPUT_$dir(1,1,$k,$j2)$Shift2), Load($mask2), re_A1_$dir);"
            Echo "im_A1_$dir =  Fmadd(LoadU(imINPUT_$dir(1,1,$k,$j2)$Shift2), Load($mask2), im_A1_$dir);"
            Echo "re_A2_$dir =  Fmadd(LoadU(reINPUT_$dir(2,1,$k,$j2)$Shift2), Load($mask2), re_A2_$dir);"
            Echo "im_A2_$dir =  Fmadd(LoadU(imINPUT_$dir(2,1,$k,$j2)$Shift2), Load($mask2), im_A2_$dir);"
            ;;
    esac

    EndIf
}

#------------------------------------------------------------------------------
function ProjectionD21_x
{
    if (( ! simd ));   then Die "ProjectionD21_x: need simd"; fi
    if [[ $mu != x ]]; then Die "ProjectionD21_x: need mu=x"; fi

    typeset j j1 j2 abs_j shift1 shift2 mask1 mask2

    eval "j=\$j_$dir"
    abs_j=abs_$j

    case $dir in
        fwd) j1=i;      j2=$abs_j; shift1=1;  shift2=1-SIMD_WIDTH; mask1=mask1110; mask2=mask0001;;
        bwd) j1=$abs_j; j2=i;      shift1=SIMD_WIDTH-1; shift2=-1; mask1=mask1000; mask2=mask0111;;
    esac 
    
    case $lang in
        C)
            Shift1="[$shift1]"; Shift2="[$shift2]";;
        Fortran)
            Shift1="($shift1+1:$shift1+SIMD_WIDTH)"; Shift2="($shift2+1:$shift2+SIMD_WIDTH)";;
    esac
    
    If "($j == i)"

    Echo "re_A1_$dir = Load(reINPUT_$dir(1,1,$k,i));"
    Echo "im_A1_$dir = Load(imINPUT_$dir(1,1,$k,i));"
    Echo "re_A2_$dir = Load(reINPUT_$dir(2,1,$k,i));"
    Echo "im_A2_$dir = Load(imINPUT_$dir(2,1,$k,i));"

    Else

    case $simdkind in
        ibm)
            Echo "re_A1_$dir = ShiftLeft2(Load(reINPUT_$dir(1,1,$k,$j1)), Load(reINPUT_$dir(1,1,$k,$j2)), $shift1);"
            Echo "im_A1_$dir = ShiftLeft2(Load(imINPUT_$dir(1,1,$k,$j1)), Load(imINPUT_$dir(1,1,$k,$j2)), $shift1);"
            Echo "re_A2_$dir = ShiftLeft2(Load(reINPUT_$dir(2,1,$k,$j1)), Load(reINPUT_$dir(2,1,$k,$j2)), $shift1);"
            Echo "im_A2_$dir = ShiftLeft2(Load(imINPUT_$dir(2,1,$k,$j1)), Load(imINPUT_$dir(2,1,$k,$j2)), $shift1);"
            ;;
        intel)
            Echo "re_A1_$dir =   Mul(LoadU(reINPUT_$dir(1,1,$k,$j1)$Shift1), Load($mask1));"
            Echo "im_A1_$dir =   Mul(LoadU(imINPUT_$dir(1,1,$k,$j1)$Shift1), Load($mask1));"
            Echo "re_A2_$dir =   Mul(LoadU(reINPUT_$dir(2,1,$k,$j1)$Shift1), Load($mask1));"
            Echo "im_A2_$dir =   Mul(LoadU(imINPUT_$dir(2,1,$k,$j1)$Shift1), Load($mask1));"

            Echo "re_A1_$dir = Fmadd(LoadU(reINPUT_$dir(1,1,$k,$j2)$Shift2), Load($mask2), re_A1_$dir);"
            Echo "im_A1_$dir = Fmadd(LoadU(imINPUT_$dir(1,1,$k,$j2)$Shift2), Load($mask2), im_A1_$dir);"
            Echo "re_A2_$dir = Fmadd(LoadU(reINPUT_$dir(2,1,$k,$j2)$Shift2), Load($mask2), re_A2_$dir);"
            Echo "im_A2_$dir = Fmadd(LoadU(imINPUT_$dir(2,1,$k,$j2)$Shift2), Load($mask2), im_A2_$dir);"
            ;;
    esac

    EndIf
}
