#include "cl_viv_vx_ext.h"

_viv_uniform VXC_512Bits uniConvertI8toI8_0_part0_2x8;
_viv_uniform VXC_512Bits uniConvertI8toI8_0_part1_2x8;
_viv_uniform VXC_512Bits uinConvertFp16ToInt8_2x8;
_viv_uniform VXC_512Bits uniConvertInt8toFp16_2x8;

__kernel void maximum_I8F16toI8
    (
    __read_only  image2d_array_t    input0,
    __read_only  image2d_array_t    input1,
    __write_only image2d_array_t    output
    )
{
    int4 coord =  (int4)(get_global_id(0), get_global_id(1), get_global_id(2), 0);

    vxc_char16 src0, src2, dst;
    vxc_short8 src1, src3, src4, src5;
    vxc_half8 data0, data1, data2, data3;
    vxc_char16 tmp0, tmp1;
    VXC_ReadImage2DArray(src0, input0, coord, VXC_5BITOFFSET_XY(0, 0),\
        VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage2DArray(src1, input1, coord, VXC_5BITOFFSET_XY(0, 0),\
        VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage2DArray(src4, input1, coord, VXC_5BITOFFSET_XY(8, 0),\
        VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));

    _viv_asm(COPY, data0, src1, 16);
    _viv_asm(COPY, data1, src4, 16);

    VXC_DP2x8(src0, src0, src0, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uniConvertI8toI8_0_part0_2x8);
    VXC_DP2x8(src0, src0, src0, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uniConvertI8toI8_0_part1_2x8);
    VXC_DP2x8(tmp0, data0, data0, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uinConvertFp16ToInt8_2x8);
    VXC_DP2x8(tmp0, data1, data1, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uinConvertFp16ToInt8_2x8);
    dst = max(src0, tmp0);

    VXC_WriteImage2DArray(output, coord, dst, VXC_MODIFIER(0, 15, 0,VXC_RM_TowardZero, 0));
}

__kernel void maximum_I8F16toI8_2D
    (
    __read_only  image2d_array_t    input0,
    __read_only  image2d_array_t    input1,
    __write_only image2d_array_t    output
    )
{
    int4 coord =  (int4)(get_global_id(0), get_global_id(1), get_global_id(1), get_global_id(1));

    vxc_char16 src0, src2, dst;
    vxc_short8 src1, src3, src4, src5;
    vxc_half8 data0, data1, data2, data3;
    vxc_char16 tmp0;

    VXC_ReadImage(src0, input0, coord.xy, VXC_5BITOFFSET_XY(0, 0),\
        VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage(src1, input1, coord.xy, VXC_5BITOFFSET_XY(0, 0),\
        VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage(src4, input1, coord.xy, VXC_5BITOFFSET_XY(8, 0),\
        VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));

    _viv_asm(COPY, data0, src1, 16);
    _viv_asm(COPY, data1, src4, 16);

    VXC_DP2x8(src0, src0, src0, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uniConvertI8toI8_0_part0_2x8);
    VXC_DP2x8(src0, src0, src0, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uniConvertI8toI8_0_part1_2x8);
    VXC_DP2x8(tmp0, data0, data0, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uinConvertFp16ToInt8_2x8);
    VXC_DP2x8(tmp0, data1, data1, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uinConvertFp16ToInt8_2x8);
    dst = max(src0, tmp0);

    VXC_WriteImage(output, coord.xy, dst, VXC_MODIFIER(0, 15, 0,VXC_RM_TowardZero, 0));
}

__kernel void maximum_I8F16toF16
    (
    __read_only  image2d_array_t    input0,
    __read_only  image2d_array_t    input1,
    __write_only image2d_array_t    output
    )
{
    int4 coord =  (int4)(get_global_id(0), get_global_id(1), get_global_id(2), 0);

    vxc_char8 vec0, vec2;
    vxc_short8 vec1, vec3, dst;
    vxc_half8  src0, src1, src2, src3;

    VXC_ReadImage2DArray(vec0, input0, coord, VXC_5BITOFFSET_XY(0, 0),\
        VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage2DArray(vec1, input1, coord, VXC_5BITOFFSET_XY(0, 0),\
        VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    _viv_asm(COPY, src1, vec1, 16);

    VXC_DP2x8(src0, vec0, vec0, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uniConvertInt8toFp16_2x8);

    VXC_VertMax3_Half(src0, src0, src1, src1, VXC_MODIFIER_CLAMP(0, 7, 0, 0));
    _viv_asm(COPY, dst, src0, 16);

    VXC_WriteImage2DArray(output, coord, dst, VXC_MODIFIER(0, 7, 0,VXC_RM_TowardZero, 0));
}

__kernel void maximum_I8F16toF16_2D
    (
    __read_only  image2d_array_t    input0,
    __read_only  image2d_array_t    input1,
    __write_only image2d_array_t    output
    )
{
    int4 coord =  (int4)(get_global_id(0), get_global_id(1), get_global_id(1), get_global_id(1));

    vxc_char8 vec0, vec2;
    vxc_short8 vec1, vec3, dst;
    vxc_half8  src0, src1, src2, src3;
    VXC_ReadImage(vec0, input0, coord.xy, VXC_5BITOFFSET_XY(0, 0),\
        VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage(vec1, input1, coord.xy, VXC_5BITOFFSET_XY(0, 0),\
        VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    _viv_asm(COPY, src1, vec1, 16);

    VXC_DP2x8(src0, vec0, vec0, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uniConvertInt8toFp16_2x8);

    VXC_VertMax3_Half(src0, src0, src1, src1, VXC_MODIFIER_CLAMP(0, 7, 0, 0));
    _viv_asm(COPY, dst, src0, 16);

    VXC_WriteImage(output, coord.xy, dst, VXC_MODIFIER(0, 7, 0,VXC_RM_TowardZero, 0));
}

_viv_uniform int2 multAndoutZP0;//[0:15] multiplier, [31:63] output zp
_viv_uniform VXC_512Bits uniU8MulAndPostShift_0_Lo_2x8;

__kernel void maximum_U8F16toF16
    (
    __read_only  image2d_array_t    input0,
    __read_only  image2d_array_t    input1,
    __write_only image2d_array_t    output
    )
{
    int4 coord =  (int4)(get_global_id(0), get_global_id(1), get_global_id(2), 0);

    vxc_uchar8 vec0, vec2;
    vxc_short8 vec1, vec3, dst;
    vxc_half8  src0, src1, src2, src3;

    VXC_ReadImage2DArray(vec0, input0, coord, VXC_5BITOFFSET_XY(0, 0),\
        VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage2DArray(vec1, input1, coord, VXC_5BITOFFSET_XY(0, 0),\
        VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    _viv_asm(COPY, src1, vec1, 16);

    vxc_ushort8 ms0;
    _viv_asm(COPY, ms0, multAndoutZP0, 16);
    VXC_DP2x8(src0, vec0, ms0, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 1),\
                uniU8MulAndPostShift_0_Lo_2x8);

    VXC_VertMax3_Half(src0, src0, src1, src1, VXC_MODIFIER_CLAMP(0, 7, 0, 0));
    _viv_asm(COPY, dst, src0, 16);

    VXC_WriteImage2DArray(output, coord, dst, VXC_MODIFIER(0, 7, 0,VXC_RM_TowardZero, 0));
}

__kernel void maximum_U8F16toF16_2D
    (
    __read_only  image2d_array_t    input0,
    __read_only  image2d_array_t    input1,
    __write_only image2d_array_t    output
    )
{
    int4 coord =  (int4)(get_global_id(0), get_global_id(1), get_global_id(1), get_global_id(1));

    vxc_uchar8 vec0, vec2;
    vxc_short8 vec1, vec3, dst;
    vxc_half8  src0, src1, src2, src3;

    VXC_ReadImage(vec0, input0, coord, VXC_5BITOFFSET_XY(0, 0),\
        VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage(vec1, input1, coord, VXC_5BITOFFSET_XY(0, 0),\
        VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    _viv_asm(COPY, src1, vec1, 16);

    vxc_ushort8 ms0;
    _viv_asm(COPY, ms0, multAndoutZP0, 16);
    VXC_DP2x8(src0, vec0, ms0, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 1),\
                uniU8MulAndPostShift_0_Lo_2x8);

    VXC_VertMax3_Half(src0, src0, src1, src1, VXC_MODIFIER_CLAMP(0, 7, 0, 0));
    _viv_asm(COPY, dst, src0, 16);

    VXC_WriteImage(output, coord, dst, VXC_MODIFIER(0, 7, 0,VXC_RM_TowardZero, 0));
}

_viv_uniform VXC_512Bits uniU8MulAndPostShift0_Lo_2x8;
_viv_uniform VXC_512Bits uniU8MulAndPostShift0_Hi_2x8;
_viv_uniform VXC_512Bits uniConvertFp16toU8_2x8;
_viv_uniform int2 multAndoutZP1;//[0:15] multiplier, [31:63] output zp
__kernel void maximum_U8F16toU8
    (
    __read_only  image2d_array_t    input0,
    __read_only  image2d_array_t    input1,
    __write_only image2d_array_t    output
    )
{
    int4 coord = (int4)(get_global_id(0), get_global_id(1), get_global_id(2), 0);

    vxc_uchar16 src0, dst0, dst1;
    vxc_ushort8 src1, src2;
    vxc_half8 data1, data2;
    VXC_ReadImage2DArray(src0, input0, coord, 0, VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage2DArray(src1, input1, coord, 0, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage2DArray(src2, input1, coord, VXC_5BITOFFSET_XY(8, 0), \
        VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    _viv_asm(COPY, data1, src1, 16);
    _viv_asm(COPY, data2, src2, 16);

    vxc_ushort8 mp0, mp1;
    _viv_asm(COPY, mp0, multAndoutZP0, 16);
    _viv_asm(COPY, mp1, multAndoutZP1, 16);
    VXC_DP2x8(dst0, src0, mp0, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1),\
        uniU8MulAndPostShift0_Lo_2x8);
    VXC_DP2x8(dst0, src0, mp0, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1),\
        uniU8MulAndPostShift0_Hi_2x8);
    VXC_DP2x8(dst1, data1, mp1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1),\
        uniConvertFp16toU8_2x8);
    VXC_DP2x8(dst1, data2, mp1, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1),\
        uniConvertFp16toU8_2x8);
    dst0 = max(dst0, dst1);

    VXC_WriteImage2DArray(output, coord, dst0, VXC_MODIFIER(0, 15, 0,VXC_RM_TowardZero, 0));
}

__kernel void maximum_U8F16toU8_2D
    (
    __read_only  image2d_array_t    input0,
    __read_only  image2d_array_t    input1,
    __write_only image2d_array_t    output
    )
{
    int2 coord = (int2)(get_global_id(0), get_global_id(1));

    vxc_uchar16 src0, dst0, dst1;
    vxc_ushort8 src1, src2;
    vxc_half8 data1, data2;
    VXC_ReadImage(src0, input0, coord, 0, VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage(src1, input1, coord, 0, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage(src2, input1, coord, VXC_5BITOFFSET_XY(8, 0), \
        VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    _viv_asm(COPY, data1, src1, 16);
    _viv_asm(COPY, data2, src2, 16);

    vxc_ushort8 mp0, mp1;
    _viv_asm(COPY, mp0, multAndoutZP0, 16);
    _viv_asm(COPY, mp1, multAndoutZP1, 16);
    VXC_DP2x8(dst0, src0, mp0, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1),\
        uniU8MulAndPostShift0_Lo_2x8);
    VXC_DP2x8(dst0, src0, mp0, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1),\
        uniU8MulAndPostShift0_Hi_2x8);
    VXC_DP2x8(dst1, data1, mp1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1),\
        uniConvertFp16toU8_2x8);
    VXC_DP2x8(dst1, data2, mp1, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1),\
        uniConvertFp16toU8_2x8);
    dst0 = max(dst0, dst1);

    VXC_WriteImage(output, coord, dst0, VXC_MODIFIER(0, 15, 0,VXC_RM_TowardZero, 0));
}

__kernel void maximum_F16F16toU8
    (
    __read_only  image2d_array_t    input0,
    __read_only  image2d_array_t    input1,
    __write_only image2d_array_t    output
    )
{
    int4 coord = (int4)(get_global_id(0), get_global_id(1), get_global_id(2), 0);

    vxc_ushort8 src0, src1;
    vxc_half8 data0, data1;
    vxc_uchar16 dst0, dst1;
    VXC_ReadImage2DArray(src0, input0, coord, 0, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage2DArray(src1, input1, coord, 0, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    _viv_asm(COPY, data0, src0, 16);
    _viv_asm(COPY, data1, src1, 16);

    vxc_ushort8 mp1;
    _viv_asm(COPY, mp1, multAndoutZP1, 16);
    VXC_DP2x8(dst0, data0, mp1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1),\
        uniConvertFp16toU8_2x8);
    VXC_DP2x8(dst1, data1, mp1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1),\
        uniConvertFp16toU8_2x8);
    dst0 = max(dst0, dst1);

    VXC_WriteImage2DArray(output, coord, dst0, VXC_MODIFIER(0, 7, 0,VXC_RM_TowardZero, 0));
}

__kernel void maximum_F16F16toU8_2D
    (
    __read_only  image2d_array_t    input0,
    __read_only  image2d_array_t    input1,
    __write_only image2d_array_t    output
    )
{
    int2 coord = (int2)(get_global_id(0), get_global_id(1));

    vxc_ushort8 src0, src1;
    vxc_half8 data0, data1;
    vxc_uchar16 dst0, dst1;
    VXC_ReadImage(src0, input0, coord, 0, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage(src1, input1, coord, 0, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    _viv_asm(COPY, data0, src0, 16);
    _viv_asm(COPY, data1, src1, 16);

    vxc_ushort8 mp1;
    _viv_asm(COPY, mp1, multAndoutZP1, 16);
    VXC_DP2x8(dst0, data0, mp1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1),\
        uniConvertFp16toU8_2x8);
    VXC_DP2x8(dst1, data1, mp1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1),\
        uniConvertFp16toU8_2x8);
    dst0 = max(dst0, dst1);

    VXC_WriteImage(output, coord, dst0, VXC_MODIFIER(0, 7, 0,VXC_RM_TowardZero, 0));
}
