#include "cl_viv_vx_ext.h"

_viv_uniform VXC_512Bits uniConvertFstDataToFp32_4x4;
_viv_uniform VXC_512Bits uniConvertSecDataToFp32_4x4;
_viv_uniform VXC_512Bits uniConvertFstDataToFp32_4x4_2;
_viv_uniform VXC_512Bits uniConvertSecDataToFp32_4x4_2;
_viv_uniform VXC_512Bits uniConvertInt32toUint8_2x8;

_viv_uniform float outScale_fl;

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

    vxc_short8 src0, src1, dst;
    vxc_half8 data1;
    VXC_ReadImage2DArray(src0, input0, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage2DArray(src1, input1, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    _viv_asm(COPY, data1, src1, 16);
    float4 x0, x1;
    float4 y0, y1;
    float4 tmpDst0, tmpDst1;
    VXC_DP4x4(x0, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertFstDataToFp32_4x4);
    VXC_DP4x4(x1, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertSecDataToFp32_4x4);
    VXC_DP4x4(y0, data1, data1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertFstDataToFp32_4x4_2);
    VXC_DP4x4(y1, data1, data1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertSecDataToFp32_4x4_2);
    float4  s0 = sign(x0);
    float4  s1 = sign(x1);
    int4 t0 = convert_int4(y0) & 1;
    int4 t1 = convert_int4(y1) & 1;
    s0 = s0 == -1 ? convert_float4(t0) == 1.0f ? -1.0f : 1.0f : s0;
    s1 = s1 == -1 ? convert_float4(t1) == 1.0f ? -1.0f : 1.0f : s1;
    tmpDst0 = s0 * exp2(y0 * log2(fabs(x0)));
    tmpDst1 = s1 * exp2(y1 * log2(fabs(x1)));

    half4 tmpVal0, tmpVal1;
    _viv_asm(CONV, tmpVal0, tmpDst0);
    _viv_asm(CONV, tmpVal1, tmpDst1);
    VXC_DP2x8(dst, tmpVal0, tmpVal1, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0), uniConvertInt32toUint8_2x8);
    VXC_WriteImage2DArray(output, coord, dst, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
}

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

    vxc_short8 src0, src1, dst;
    vxc_half8 data1;
    VXC_ReadImage(src0, input0, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage(src1, input1, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    _viv_asm(COPY, data1, src1, 16);
    float4 x0, x1;
    float4 y0, y1;
    float4 tmpDst0, tmpDst1;
    VXC_DP4x4(x0, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertFstDataToFp32_4x4);
    VXC_DP4x4(x1, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertSecDataToFp32_4x4);
    VXC_DP4x4(y0, data1, data1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertFstDataToFp32_4x4_2);
    VXC_DP4x4(y1, data1, data1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertSecDataToFp32_4x4_2);
    float4  s0 = sign(x0);
    float4  s1 = sign(x1);
    int4 t0 = convert_int4(y0) & 1;
    int4 t1 = convert_int4(y1) & 1;
    s0 = s0 == -1 ? convert_float4(t0) == 1.0f ? -1.0f : 1.0f : s0;
    s1 = s1 == -1 ? convert_float4(t1) == 1.0f ? -1.0f : 1.0f : s1;
    tmpDst0 = s0 * exp2(y0 * log2(fabs(x0)));
    tmpDst1 = s1 * exp2(y1 * log2(fabs(x1)));

    half4 tmpVal0, tmpVal1;
    _viv_asm(CONV, tmpVal0, tmpDst0);
    _viv_asm(CONV, tmpVal1, tmpDst1);
    VXC_DP2x8(dst, tmpVal0, tmpVal1, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0), uniConvertInt32toUint8_2x8);
    VXC_WriteImage(output, coord, dst, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
}

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

    vxc_short8 src0, src1, dst;
    vxc_half8 data1;
    VXC_ReadImage2DArray(src0, input0, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage2DArray(src1, input1, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    _viv_asm(COPY, data1, src1, 16);
    float4 x0, x1;
    float4 y0, y1;
    float4 tmpDst0, tmpDst1;
    VXC_DP4x4(x0, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertFstDataToFp32_4x4);
    VXC_DP4x4(x1, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertSecDataToFp32_4x4);
    VXC_DP4x4(y0, data1, data1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertFstDataToFp32_4x4_2);
    VXC_DP4x4(y1, data1, data1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertSecDataToFp32_4x4_2);
    float4  s0 = sign(x0);
    float4  s1 = sign(x1);
    int4 t0 = convert_int4(y0) & 1;
    int4 t1 = convert_int4(y1) & 1;
    s0 = s0 == -1 ? convert_float4(t0) == 1.0f ? -1.0f : 1.0f : s0;
    s1 = s1 == -1 ? convert_float4(t1) == 1.0f ? -1.0f : 1.0f : s1;
    tmpDst0 = s0 * exp2(y0 * log2(fabs(x0)));
    tmpDst1 = s1 * exp2(y1 * log2(fabs(x1)));

    int4 tmpVal0 = convert_int4_rte(tmpDst0 * outScale_fl);
    int4 tmpVal1 = convert_int4_rte(tmpDst1 * outScale_fl);
    VXC_DP2x8(dst, tmpVal0, tmpVal1, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 1),\
            uniConvertInt32toUint8_2x8);
    VXC_WriteImage2DArray(output, coord, dst, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
}

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

    vxc_short8 src0, src1, dst;
    vxc_half8 data1;
    VXC_ReadImage(src0, input0, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage(src1, input1, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    _viv_asm(COPY, data1, src1, 16);
    float4 x0, x1;
    float4 y0, y1;
    float4 tmpDst0, tmpDst1;
    VXC_DP4x4(x0, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertFstDataToFp32_4x4);
    VXC_DP4x4(x1, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertSecDataToFp32_4x4);
    VXC_DP4x4(y0, data1, data1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertFstDataToFp32_4x4_2);
    VXC_DP4x4(y1, data1, data1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertSecDataToFp32_4x4_2);
    float4  s0 = sign(x0);
    float4  s1 = sign(x1);
    int4 t0 = convert_int4(y0) & 1;
    int4 t1 = convert_int4(y1) & 1;
    s0 = s0 == -1 ? convert_float4(t0) == 1.0f ? -1.0f : 1.0f : s0;
    s1 = s1 == -1 ? convert_float4(t1) == 1.0f ? -1.0f : 1.0f : s1;
    tmpDst0 = s0 * exp2(y0 * log2(fabs(x0)));
    tmpDst1 = s1 * exp2(y1 * log2(fabs(x1)));

    int4 tmpVal0 = convert_int4_rte(tmpDst0 * outScale_fl);
    int4 tmpVal1 = convert_int4_rte(tmpDst1 * outScale_fl);
    VXC_DP2x8(dst, tmpVal0, tmpVal1, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 1),\
            uniConvertInt32toUint8_2x8);
    VXC_WriteImage(output, coord, dst, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
}

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

    vxc_short8 src0, src1, dst;
    VXC_ReadImage2DArray(src0, input0, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage2DArray(src1, input1, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    float4 x0, x1;
    float4 y0, y1;
    float4 tmpDst0, tmpDst1;
    VXC_DP4x4(x0, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertFstDataToFp32_4x4);
    VXC_DP4x4(x1, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertSecDataToFp32_4x4);
    VXC_DP4x4(y0, src1, src1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertFstDataToFp32_4x4_2);
    VXC_DP4x4(y1, src1, src1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertSecDataToFp32_4x4_2);
    float4  s0 = sign(x0);
    float4  s1 = sign(x1);
    int4 t0 = convert_int4(y0) & 1;
    int4 t1 = convert_int4(y1) & 1;
    s0 = s0 == -1 ? convert_float4(t0) == 1.0f ? -1.0f : 1.0f : s0;
    s1 = s1 == -1 ? convert_float4(t1) == 1.0f ? -1.0f : 1.0f : s1;
    tmpDst0 = s0 * exp2(y0 * log2(fabs(x0)));
    tmpDst1 = s1 * exp2(y1 * log2(fabs(x1)));

    int4 tmpVal0 = convert_int4_rte(tmpDst0 * outScale_fl);
    int4 tmpVal1 = convert_int4_rte(tmpDst1 * outScale_fl);
    VXC_DP2x8(dst, tmpVal0, tmpVal1, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 1),\
            uniConvertInt32toUint8_2x8);
    VXC_WriteImage2DArray(output, coord, dst, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
}

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

    vxc_short8 src0, src1, dst;
    VXC_ReadImage(src0, input0, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage(src1, input1, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    float4 x0, x1;
    float4 y0, y1;
    float4 tmpDst0, tmpDst1;
    VXC_DP4x4(x0, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertFstDataToFp32_4x4);
    VXC_DP4x4(x1, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertSecDataToFp32_4x4);
    VXC_DP4x4(y0, src1, src1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertFstDataToFp32_4x4_2);
    VXC_DP4x4(y1, src1, src1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniConvertSecDataToFp32_4x4_2);
    float4  s0 = sign(x0);
    float4  s1 = sign(x1);
    int4 t0 = convert_int4(y0) & 1;
    int4 t1 = convert_int4(y1) & 1;
    s0 = s0 == -1 ? convert_float4(t0) == 1.0f ? -1.0f : 1.0f : s0;
    s1 = s1 == -1 ? convert_float4(t1) == 1.0f ? -1.0f : 1.0f : s1;
    tmpDst0 = s0 * exp2(y0 * log2(fabs(x0)));
    tmpDst1 = s1 * exp2(y1 * log2(fabs(x1)));

    int4 tmpVal0 = convert_int4_rte(tmpDst0 * outScale_fl);
    int4 tmpVal1 = convert_int4_rte(tmpDst1 * outScale_fl);
    VXC_DP2x8(dst, tmpVal0, tmpVal1, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 1),\
            uniConvertInt32toUint8_2x8);
    VXC_WriteImage(output, coord, dst, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
}