#include "cl_viv_vx_ext.h"

_viv_uniform VXC_512Bits uniU8ConvS16_Stpe0_8x2b;
_viv_uniform VXC_512Bits uniU8ConvS16_Stpe1_8x2b;
_viv_uniform VXC_512Bits uniU8SubZp_lo_2x8;
_viv_uniform VXC_512Bits uniU8SubZp_hi_2x8;
_viv_uniform VXC_512Bits uniExtractInteger_2x8;
_viv_uniform VXC_512Bits uniU8ConvS16_Stpe4_8x2b;
_viv_uniform VXC_512Bits uniU8ConvS16_Stpe5_8x2b;
_viv_uniform int weightZP;
_viv_uniform float outputZP;
_viv_uniform float scale;

__kernel void vxDW_Conv1D_U8toU8_K88_D2(
__read_only  image2d_array_t  input,
__read_only  image2d_array_t  weight,
__read_only  image2d_t        bias,
__write_only image2d_array_t  output,
int              pad,
int              stride,
int              dilation)
{
int4 coord_in = (int4)(get_global_id(0) * stride - pad + 16,\
get_global_id(0) * stride - pad + 48, get_global_id(1), 0);

vxc_uchar32 src0, src1;
vxc_uchar16 inData[12];
vxc_uchar16 wData[6];
int4 sumA, sumB;

sumA = read_imagei(bias, coord_in.zw);

VXC_ReadImage(inData[0], input, coord_in.xz, VXC_5BITOFFSET_XY(-16, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
VXC_ReadImage(inData[1], input, coord_in.xz, VXC_5BITOFFSET_XY(0, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
VXC_ReadImage(inData[2], input, coord_in.yz, VXC_5BITOFFSET_XY(-16, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
VXC_ReadImage(inData[3], input, coord_in.yz, VXC_5BITOFFSET_XY(0, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
coord_in.xy += 64;
VXC_ReadImage(inData[4], input, coord_in.xz, VXC_5BITOFFSET_XY(-16, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
VXC_ReadImage(inData[5], input, coord_in.xz, VXC_5BITOFFSET_XY(0, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
VXC_ReadImage(inData[6], input, coord_in.yz, VXC_5BITOFFSET_XY(-16, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
VXC_ReadImage(inData[7], input, coord_in.yz, VXC_5BITOFFSET_XY(0, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
coord_in.xy += 64;
VXC_ReadImage(inData[8], input, coord_in.xz, VXC_5BITOFFSET_XY(-16, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
VXC_ReadImage(inData[9], input, coord_in.xz, VXC_5BITOFFSET_XY(0, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
VXC_ReadImage(inData[10], input, coord_in.yz, VXC_5BITOFFSET_XY(-16, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
VXC_ReadImage(inData[11], input, coord_in.yz, VXC_5BITOFFSET_XY(0, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));

int4 coord = (int4)(get_global_id(0), 16, 48, get_global_id(1));

VXC_ReadImage(wData[0], weight, coord.yw, VXC_5BITOFFSET_XY(-16, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
VXC_ReadImage(wData[1], weight, coord.yw, VXC_5BITOFFSET_XY(0, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
VXC_ReadImage(wData[2], weight, coord.zw, VXC_5BITOFFSET_XY(-16, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
VXC_ReadImage(wData[3], weight, coord.zw, VXC_5BITOFFSET_XY(0, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
coord.yz += 64;
VXC_ReadImage(wData[4], weight, coord.yw, VXC_5BITOFFSET_XY(-16, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
VXC_ReadImage(wData[5], weight, coord.yw, VXC_5BITOFFSET_XY(0, 0),\
VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));

sumA = sumA.xxxx;
sumB = sumA;

int4 sum0, sum1;
vxc_uchar4 zp;
_viv_asm(COPY, zp, weightZP, 4);

vxc_short8 coef;
src0.hi = inData[0];
src0.lo = inData[1];

VXC_DP2x8(coef, wData[0], zp, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0), uniU8SubZp_lo_2x8);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe0_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe1_8x2b);
sumA += sum0;

VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe4_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe5_8x2b);
sumB += sum0;

src0.hi = src0.lo;
src0.lo = inData[2];

VXC_DP2x8(coef, wData[0], zp, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0), uniU8SubZp_hi_2x8);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe0_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe1_8x2b);
sumA += sum0;

VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe4_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe5_8x2b);
sumB += sum0;
src0.hi = inData[2];
src0.lo = inData[3];
VXC_DP2x8(coef, wData[1], zp, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0), uniU8SubZp_lo_2x8);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe0_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe1_8x2b);
sumA += sum0;
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe4_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe5_8x2b);
sumB += sum0;

src0.hi = src0.lo;
src0.lo = inData[4];

VXC_DP2x8(coef, wData[1], zp, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0), uniU8SubZp_hi_2x8);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe0_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe1_8x2b);
sumA += sum0;

VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe4_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe5_8x2b);
sumB += sum0;
src0.hi = inData[4];
src0.lo = inData[5];

VXC_DP2x8(coef, wData[2], zp, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0), uniU8SubZp_lo_2x8);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe0_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe1_8x2b);
sumA += sum0;

VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe4_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe5_8x2b);
sumB += sum0;

src0.hi = src0.lo;
src0.lo = inData[6];

VXC_DP2x8(coef, wData[2], zp, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0), uniU8SubZp_hi_2x8);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe0_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe1_8x2b);
sumA += sum0;

VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe4_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe5_8x2b);
sumB += sum0;
src0.hi = inData[6];
src0.lo = inData[7];
VXC_DP2x8(coef, wData[3], zp, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0), uniU8SubZp_lo_2x8);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe0_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe1_8x2b);
sumA += sum0;
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe4_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe5_8x2b);
sumB += sum0;
src0.hi = src0.lo;
src0.lo = inData[8];
VXC_DP2x8(coef, wData[3], zp, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0), uniU8SubZp_hi_2x8);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe0_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe1_8x2b);
sumA += sum0;
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe4_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe5_8x2b);
sumB += sum0;

src0.hi = inData[8];
src0.lo = inData[9];
VXC_DP2x8(coef, wData[4], zp, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0), uniU8SubZp_lo_2x8);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe0_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe1_8x2b);
sumA += sum0;
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe4_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe5_8x2b);
sumB += sum0;
src0.hi = src0.lo;
src0.lo = inData[10];
VXC_DP2x8(coef, wData[4], zp, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0), uniU8SubZp_hi_2x8);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe0_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe1_8x2b);
sumA += sum0;
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe4_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe5_8x2b);
sumB += sum0;
src0.hi = inData[10];
src0.lo = inData[11];
VXC_DP2x8(coef, wData[5], zp, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0), uniU8SubZp_lo_2x8);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe0_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe1_8x2b);
sumA += sum0;
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(0, 1, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe4_8x2b);
VXC_DP8x2_b(sum0, src0.hi, src0.lo, coef, VXC_MODIFIER(2, 3, 0, VXC_RM_TowardZero, 0), uniU8ConvS16_Stpe5_8x2b);
sumB += sum0;
float4 result0 = convert_float4(sumA) * scale + outputZP;
float4 result1 = convert_float4(sumB) * scale + outputZP;
int4 dst0 = convert_int4(result0);
int4 dst1 = convert_int4(result1);
vxc_uchar16 dst;
VXC_DP2x8(dst, dst0, dst1, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 1), uniExtractInteger_2x8);
VXC_WriteImage(output, coord.xw, dst, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
}

