aaron had to go touch my code...

aaron had to go touch my code...

kernel void toSepia(read_only image2d_t srcImg, write_only image2d_t dstImg)
{
  const sampler_t smp =
    CLK_NORMALIZE_COORDS_FALSE | //Natural coordinates
    CLK_ADDRESS_CLAMP_TO_EDGE | //Clamp to zeros
    CLK_FILTER_LINEAR;

  int2 coord = (int2)(get_global_id(0), get_global_id(1));

  uint4 rgba = read_imageui(srcImg, smp, coord); //The byte order is RGBA

  float4 rgbafloat = convert_float4(rgba) / 255.0f; //Convert to normalized [0..1] float

  //Convert RGB to luminance (make the image sepia).
  float luminance = sqrt(0.43f * rbgafloat.z * rbgafloat.z + 0.74f * rbgafloat.y * rbgafloat.y + 1.07f * rbgafloat.x * rbgafloat.x);

  rgba.x = rgba.y = rgba.z = (uint) (luminance * 255.0f);
  rgba.w = 255;

  write_imageui(dstImg, coord, rgba);
}

kernel void toSepia(read_only image2d_t srcImg, write_only image2d_t dstImg)
{
  const sampler_t smp =
    CLK_NORMALIZE_COORDS_FALSE | //Natural coordinates
    CLK_ADDRESS_CLAMP_TO_EDGE | //Clamp to zeros
    CLK_FILTER_LINEAR;

  int2 coord = (int2)(get_global_id(0), get_global_id(1));

  uint4 rgba = read_imageui(srcImg, smp, coord); //The byte order is RGBA

  float4 rgbafloat = convert_float4(rgba) / 255.0f; //Convert to normalized [0..1] float

  //Convert RGB to luminance (make the image sepia).
  float luminance = sqrt(0.43f * rbgafloat.z * rbgafloat.z + 0.74f * rbgafloat.y * rbgafloat.y + 1.07f * rbgafloat.x * rbgafloat.x);

  rgba.x = rgba.y = rgba.z = (uint) (rgba.z * 255.0f);
  rgba.w = 255;

  write_imageui(dstImg, coord, rgba);
}


Fix some errors

Fix some errors

//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
//    Niko Li, newlife20080214@gmail.com
//    Rock Li, Rock.li@amd.com
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors as is and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//

#if lcn == 1
    #if dcn == 4
        #define LUT_OP(num)\
            __global const uchar4 *idx = (__global const uchar4 *)(srcptr + mad24(num, src_step, src_index));\
            dst = (__global dstT *)(dstptr + mad24(num, dst_step, dst_index));\
            dst[0] = lut_l[idx->x];\
            dst[1] = lut_l[idx->y];\
            dst[2] = lut_l[idx->z];\
            dst[3] = lut_l[idx->w];
    #elif dcn == 3
        #define LUT_OP(num)\
            uchar3 idx = vload3(0, (__global const uchar *)(srcptr + mad24(num, src_step, src_index)));\
            dst = (__global dstT *)(dstptr + mad24(num, dst_step, dst_index));\
            dst[0] = lut_l[idx.x];\
            dst[1] = lut_l[idx.y];\
            dst[2] = lut_l[idx.z];
    #elif dcn == 2
        #define LUT_OP(num)\
            __global const uchar2 * idx = (__global const uchar *)(srcptr + mad24(num, src_step, src_index));\
            dst = (__global dstT *)(dstptr + mad24(num, dst_step, dst_index));\
            dst[0] = lut_l[idx->x];\
            dst[1] = lut_l[idx->y];
    #elif dcn == 1
        #define LUT_OP(num)\
            uchar idx = (__global const uchar *)(srcptr + mad24(num, src_step, src_index))[0];\
            dst = (__global dstT *)(dstptr + mad24(num, dst_step, dst_index));\
            dst[0] = lut_l[idx];
    #else
        #define LUT_OP(num)\
            src = (__global const srcT *)(srcptr + mad24(num, src_step, src_index));\
            dst = (__global dstT *)(dstptr + mad24(num, dst_step, dst_index));\
            for (int cn = 0; cn < dcn; ++cn)\
                dst[cn] = lut_l[src[cn]];
    #endif
#else
    #if dcn == 4
        #define LUT_OP(num)\
            __global const uchar4 *src_pixel = (__global const uchar4 *)(srcptr + mad24(num, src_step, src_index));\
            int4 idx = convert_int4(src_pixel[0]) * lcn + (int4)(0, 1, 2, 3);\
            dst = (__global dstT *)(dstptr + mad24(num, dst_step, dst_index));\
            dst[0] = lut_l[idx.x];\
            dst[1] = lut_l[idx.y];\
            dst[2] = lut_l[idx.z];\
            dst[3] = lut_l[idx.w];
    #elif dcn == 3
        #define LUT_OP(num)\
            uchar3 src_pixel = vload3(0, (__global const uchar *)(srcptr + mad24(num, src_step, src_index)));\
            int3 idx = convert_int3(src_pixel) * lcn + (int3)(0, 1, 2);\
            dst = (__global dstT *)(dstptr + mad24(num, dst_step, dst_index));\
            dst[0] = lut_l[idx.x];\
            dst[1] = lut_l[idx.y];\
            dst[2] = lut_l[idx.z];
    #elif dcn == 2
        #define LUT_OP(num)\
            __global const uchar2 *src_pixel = (__global const uchar2 *)(srcptr + mad24(num, src_step, src_index));\
            int2 idx = convert_int2(src_pixel[0]) * lcn + (int2)(0, 1);\
            dst = (__global dstT *)(dstptr + mad24(num, dst_step, dst_index));\
            dst[0] = lut_l[idx.x];\
            dst[1] = lut_l[idx.y];
    #elif dcn == 1 //error case (1 < lcn) ==> lcn == scn == dcn
        #define LUT_OP(num)\
            uchar idx = (__global const uchar *)(srcptr + mad24(num, src_step, src_index))[0];\
            dst = (__global dstT *)(dstptr + mad24(num, dst_step, dst_index));\
            dst[0] = lut_l[idx];
    #else
        #define LUT_OP(num)\
            src = (__global const srcT *)(srcptr + mad24(num, src_step, src_index));\
            dst = (__global dstT *)(dstptr + mad24(num, dst_step, dst_index));\
            for (int cn = 0; cn < dcn; ++cn)\
                dst[cn] = lut_l[mad24(src[cn], lcn, cn)];
    #endif
#endif

#define LOCAL_LUT_INIT\
    {\
        __global const dstT * lut = (__global const dstT *)(lutptr + lut_offset);\
        int init = mad24((int)get_local_id(1), (int)get_local_size(0), (int)get_local_id(0));\
        int step = get_local_size(0) * get_local_size(1);\
        for (int i = init; i < 256 * lcn; i += step)\
        {\
            lut_l[i] = lut[i];\
        }\
        barrier(CLK_LOCAL_MEM_FENCE);\
    }

__kernel void LUT(__global const uchar * srcptr, int src_step, int src_offset,
                  __global const uchar * lutptr, int lut_step, int lut_offset,
                  __global uchar * dstptr, int dst_step, int dst_offset, int rows, int cols)
{
    __local dstT lut_l[256 * lcn];
    LOCAL_LUT_INIT;

    int x = get_global_id(0);
    int y = 4 * get_global_id(1);

    if (x < cols && y < rows)
    {
        int src_index = mad24(y, src_step, mad24(x, (int)sizeof(srcT) * dcn, src_offset));
        int dst_index = mad24(y, dst_step, mad24(x, (int)sizeof(dstT) * dcn, dst_offset));
        __global const srcT * src; __global dstT * dst;
        int tmp_idx;
        LUT_OP(0);
        if (y < rows - 1)
        {
            LUT_OP(1);
            if (y < rows - 2)
            {
                LUT_OP(2);
                if (y < rows - 3)
                {
                    LUT_OP(3);
                }
            }
        }

    }
}

//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
//    Niko Li, newlife20080214@gmail.com
//    Rock Li, Rock.li@amd.com
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors as is and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//

#if lcn == 1
    #if dcn == 4
        #define LUT_OP(num)\
            uchar4 idx = vload4(0, (__global const uchar *)(srcptr + src_index  + num * src_step));\
            dst = (__global dstT *)(dstptr + dst_index + num * dst_step);\
            dst[0] = lut_l[idx.x];\
            dst[1] = lut_l[idx.y];\
            dst[2] = lut_l[idx.z];\
            dst[3] = lut_l[idx.w];
    #elif dcn == 3
        #define LUT_OP(num)\
            uchar3 idx = vload3(0, (__global const uchar *)(srcptr + src_index  + num * src_step));\
            dst = (__global dstT *)(dstptr + dst_index + num * dst_step);\
            dst[0] = lut_l[idx.x];\
            dst[1] = lut_l[idx.y];\
            dst[2] = lut_l[idx.z];
    #elif dcn == 2
        #define LUT_OP(num)\
            uchar2 idx = vload2(0, (__global const uchar *)(srcptr + src_index  + num * src_step));\
            dst = (__global dstT *)(dstptr + dst_index + num * dst_step);\
            dst[0] = lut_l[idx.x];\
            dst[1] = lut_l[idx.y];
    #elif dcn == 1
        #define LUT_OP(num)\
            uchar idx = (__global const uchar *)(srcptr + src_index  + num * src_step)[0];\
            dst = (__global dstT *)(dstptr + dst_index + num * dst_step);\
            dst[0] = lut_l[idx];
    #else
        #define LUT_OP(num)\
            src = (__global const srcT *)(srcptr + src_index + num * src_step);\
            dst = (__global dstT *)(dstptr + dst_index + num * dst_step);\
            for (int cn = 0; cn < dcn; ++cn)\
                dst[cn] = lut_l[src[cn]];
    #endif
#else
    #if dcn == 4
        #define LUT_OP(num)\
            uchar4 src_pixel = vload4(0, (__global const uchar *)(srcptr + src_index  + num * src_step));\
            int4 idx = convert_int4(src_pixel) * lcn + (int4)(0, 1, 2, 3);\
            dst = (__global dstT *)(dstptr + dst_index + num * dst_step);\
            dst[0] = lut_l[idx.x];\
            dst[1] = lut_l[idx.y];\
            dst[2] = lut_l[idx.z];\
            dst[3] = lut_l[idx.w];
    #elif dcn == 3
        #define LUT_OP(num)\
            uchar3 src_pixel = vload3(0, (__global const uchar *)(srcptr + src_index  + num * src_step));\
            int3 idx = convert_int3(src_pixel) * lcn + (int3)(0, 1, 2);\
            dst = (__global dstT *)(dstptr + dst_index + num * dst_step);\
            dst[0] = lut_l[idx.x];\
            dst[1] = lut_l[idx.y];\
            dst[2] = lut_l[idx.z];
    #elif dcn == 2
        #define LUT_OP(num)\
            uchar2 src_pixel = vload2(0, (__global const uchar *)(srcptr + src_index  + num * src_step));\
            int2 idx = convert_int2(src_pixel) * lcn + (int2)(0, 1);\
            dst = (__global dstT *)(dstptr + dst_index + num * dst_step);\
            dst[0] = lut_l[idx.x];\
            dst[1] = lut_l[idx.y];
    #elif dcn == 1 //error case (1 < lcn) ==> lcn == scn == dcn
        #define LUT_OP(num)\
            uchar idx = (__global const uchar *)(srcptr + src_index  + num * src_step)[0];\
            dst = (__global dstT *)(dstptr + dst_index + num * dst_step);\
            dst[0] = lut_l[idx];
    #else
        #define LUT_OP(num)\
            src = (__global const srcT *)(srcptr + src_index + num * src_step);\
            dst = (__global dstT *)(dstptr + dst_index + num * dst_step);\
            for (int cn = 0; cn < dcn; ++cn)\
                dst[cn] = lut_l[mad24(src[cn], lcn, cn)];
    #endif
#endif

#define LOCAL_LUT_INIT\
    {\
        __global const dstT * lut = (__global const dstT *)(lutptr + lut_offset);\
        int init = mad24((int)get_local_id(1), (int)get_local_size(0), (int)get_local_id(0));\
        int step = get_local_size(0) * get_local_size(1);\
        for (int i = init; i < 256 * lcn; i += step)\
        {\
            lut_l[i] = lut[i];\
        }\
        barrier(CLK_LOCAL_MEM_FENCE);\
    }

__kernel void LUT(__global const uchar * srcptr, int src_step, int src_offset,
                  __global const uchar * lutptr, int lut_step, int lut_offset,
                  __global uchar * dstptr, int dst_step, int dst_offset, int rows, int cols)
{
    __local dstT lut_l[256 * lcn];
    LOCAL_LUT_INIT;

    int x = get_global_id(0);
    int y = 4 * get_global_id(1);

    if (x < cols && y < rows)
    {
        int src_index = mad24(y, src_step, mad24(x, (int)sizeof(srcT) * dcn, src_offset));
        int dst_index = mad24(y, dst_step, mad24(x, (int)sizeof(dstT) * dcn, dst_offset));
        __global const srcT * src; __global dstT * dst;

        LUT_OP(0);
        if (y < rows - 1)
        {
            LUT_OP(1);
            if (y < rows - 2)
            {
                LUT_OP(2);
                if (y < rows - 3)
                {
                    LUT_OP(3);
                }
            }
        }

    }
}


OpenCL implementation of RANMAR PRNG

OpenCL implementation of RANMAR PRNG

/******************************************************************************
 * @file     prngcl_ranmar.cl
 * @author   Vadim Demchik <vadimdi@yahoo.com>
 * @version  1.1.1
 *
 * @brief    [PRNGCL library]
 *           contains OpenCL implementation of RANMAR pseudo-random number generator
 *
 *
 * @section  CREDITS
 *
 *   George Marsaglia, Arif Zaman and Wai Wan Tsang,
 *   "Toward a universal random number generator",
 *   Statistics & Probability Letters, 9 (1990), 35--39.
 *
 *   F. James,
 *   "A review of pseudorandom number generators",
 *   Computer Physics Communications, 60 (1990), 329--344.
 *
 *
 * @section  LICENSE
 *
 * Copyright (c) 2013, 2014 Vadim Demchik
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *    Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *****************************************************************************/

#ifndef PRNGCL_RANMAR_CL
#define PRNGCL_RANMAR_CL

#include "prngcl_common.cl"

#define RM_min    (1.0/16777216.0)
#define RM_max    (16777215.0/16777216.0)
#define RM_k      (5.9604644775390625E-8) // 1/2^24

#define RM_CD (7654321.0f / 16777216.0f)
#define RM_CM (16777213.0f /16777216.0f)

//________________________________________________________________________________________________________ RANMAR PRNG
__kernel void
ranmar_init(const __global uint4* seeds, __global float4* seedtable)
{
    float4 seed;
    //
    uint4 RM_seed1 = seeds[GID];
    uint4 RM_seed2 = seeds[GID + GID_SIZE];
    //
    uint4 i = ((RM_seed1 / 177) % 177) + 2;
    uint4 j = (RM_seed1 % 177) + 2;
    uint4 k = ((RM_seed2 / 169) % 178) + 1;
    uint4 l = (RM_seed2 % 169);
    for (int n = 0; n < 97; n++)
    {
        uint4 s = (uint4) 0;
        uint  t = 8388608;
        for (int m = 0; m < 24;  m++)
        {
            uint4 u = (i * j) % 179;
            u = (u * k) % 179;
            i = j;
            j = k;
            k = u;
            l = (53 * l + 1) % 169;
            uint4 lus = (l * u) % 64;

            if ( lus.x >= 32) s.x += t;
            if ( lus.y >= 32) s.y += t;
            if ( lus.z >= 32) s.z += t;
            if ( lus.w >= 32) s.w += t;
            t = t >> 1;
        }
        seed.x = ((float) s.x);
        seed.y = ((float) s.y);
        seed.z = ((float) s.z);
        seed.w = ((float) s.w);
        seedtable[GID + GID_SIZE * n] = seed / ((float4) 16777216.0f);
	}
    Uint_and_Float indx_I97, indx_J97;
    indx_I97.uint_value = 96;
    indx_J97.uint_value = 32;
    float4 indx;
    indx.x = indx_I97.float_value;
    indx.y = indx_J97.float_value;
    indx.z = (362436.0f / 16777216.0f);
    indx.w = 0.0f;

    seedtable[GID + GID_SIZE * 97] = indx;   // (RM_I97,RM_J97,RM_C,0)
}

__attribute__((always_inline)) float4
rm_step(__global float4 * seedtable,uint* RM_I97,uint* RM_J97,float* uniz)
{
        float4 uni;
        uni = seedtable[GID + GID_SIZE * (*RM_I97)] - seedtable[GID + GID_SIZE * (*RM_J97)];
	    uni = select(uni, (uni + 1.0f), uni < (float4) 0.0f);
        seedtable[GID + GID_SIZE * (*RM_I97)] = uni;

	    if ((*RM_I97) == 0) (*RM_I97) = 97;
	    if ((*RM_J97) == 0) (*RM_J97) = 97;
	    (*RM_I97)--;
	    (*RM_J97)--;

        (*uniz) -= RM_CD;
	    if ((*uniz) < 0.0) {(*uniz) += RM_CM;}
        uni -= (*uniz);
	    uni = select(uni, (uni + 1.0f), uni < (float4) 0.0f);
        return uni;
}

#ifdef PRECISION_DOUBLE  // if double precision is defined
__attribute__((always_inline)) hgpu_double4
rm_step_double(__global float4 * seedtable,uint* RM_I97,uint* RM_J97,float* uniz)
{
    hgpu_double4 result;
    float4 rnd1 = 0.0;
    float4 rnd2;
#ifndef PRNG_SKIP_CHECK
    while ((rnd1.x <= RM_min) || (rnd1.x >= RM_max) ||
           (rnd1.y <= RM_min) || (rnd1.y >= RM_max) ||
           (rnd1.z <= RM_min) || (rnd1.z >= RM_max) ||
           (rnd1.w <= RM_min) || (rnd1.w >= RM_max)
          )
#endif
        rnd1 = rm_step(seedtable,RM_I97,RM_J97,uniz);
    rnd2 = rm_step(seedtable,RM_I97,RM_J97,uniz);

    result = hgpu_float4_to_double4(rnd1,rnd2,RM_min,RM_max,RM_k);
    return result;
}
#endif

__kernel void
ranmar(__global float4 * seedtable,__global hgpu_float4 * prns, const uint samples)
{
    uint giddst = GID;
    float4 uni = (float4) 0.0;
    Uint_and_Float indx_I97, indx_J97;
    float4 indx = seedtable[GID + GID_SIZE * 97];
    indx_I97.float_value = indx.x;
    indx_J97.float_value = indx.y;
    uint RM_I97 = indx_I97.uint_value;
    uint RM_J97 = indx_J97.uint_value;
    float uniz = indx.z;
    for (uint i=0; i<samples; i++) {
#ifdef PRECISION_DOUBLE // if double precision is defined
        hgpu_double4 result = rm_step_double(seedtable,&RM_I97,&RM_J97,&uniz);
        prns[giddst] = result;
#else
        uni = rm_step(seedtable,&RM_I97,&RM_J97,&uniz);
        prns[giddst] = uni;
#endif
        giddst += GID_SIZE;
    }

    indx_I97.uint_value = RM_I97;
    indx_J97.uint_value = RM_J97;
    indx.z = uniz;
    indx.x = indx_I97.float_value;
    indx.y = indx_J97.float_value;
    seedtable[GID + GID_SIZE * 97] = indx;
}

#endif

/******************************************************************************
 * @file     prngcl_ranmar.cl
 * @author   Vadim Demchik <vadimdi@yahoo.com>
 * @version  1.1.1
 *
 * @brief    [PRNGCL library]
 *           contains OpenCL implementation of RANMAR pseudo-random number generator
 *
 *
 * @section  CREDITS
 *
 *   George Marsaglia, Arif Zaman and Wai Wan Tsang,
 *   "Toward a universal random number generator",
 *   Statistics & Probability Letters, 9 (1990), 35--39.
 *
 *   F. James,
 *   "A review of pseudorandom number generators",
 *   Computer Physics Communications, 60 (1990), 329--344.
 *
 *
 * @section  LICENSE
 *
 * Copyright (c) 2013, 2014 Vadim Demchik
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *    Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *****************************************************************************/

#ifndef PRNGCL_RANMAR_CL
#define PRNGCL_RANMAR_CL

#include "prngcl_common.cl"

#define RM_min    (1.0/16777216.0)
#define RM_max    (16777215.0/16777216.0)
#define RM_k      (5.9604644775390625E-8) // 1/2^24

#define RM_left   (RM_min+RM_k*RM_max)
#define RM_right  (RM_max+RM_k*RM_min)

#define RM_CD (7654321.0f / 16777216.0f)
#define RM_CM (16777213.0f /16777216.0f)

//________________________________________________________________________________________________________ RANMAR PRNG
__kernel void
ranmar_init(const __global uint4* seeds, __global float4* seedtable)
{
    float4 seed;
    //
    uint4 RM_seed1 = seeds[GID];
    uint4 RM_seed2 = seeds[GID + GID_SIZE];
    //
    uint4 i = ((RM_seed1 / 177) % 177) + 2;
    uint4 j = (RM_seed1 % 177) + 2;
    uint4 k = ((RM_seed2 / 169) % 178) + 1;
    uint4 l = (RM_seed2 % 169);
    for (int n = 0; n < 97; n++)
    {
        uint4 s = (uint4) 0;
        uint  t = 8388608;
        for (int m = 0; m < 24;  m++)
        {
            uint4 u = (i * j) % 179;
            u = (u * k) % 179;
            i = j;
            j = k;
            k = u;
            l = (53 * l + 1) % 169;
            uint4 lus = (l * u) % 64;

            if ( lus.x >= 32) s.x += t;
            if ( lus.y >= 32) s.y += t;
            if ( lus.z >= 32) s.z += t;
            if ( lus.w >= 32) s.w += t;
            t = t >> 1;
        }
        seed.x = ((float) s.x);
        seed.y = ((float) s.y);
        seed.z = ((float) s.z);
        seed.w = ((float) s.w);
        seedtable[GID + GID_SIZE * n] = seed / ((float4) 16777216.0f);
	}
    Uint_and_Float indx_I97, indx_J97;
    indx_I97.uint_value = 96;
    indx_J97.uint_value = 32;
    float4 indx;
    indx.x = indx_I97.float_value;
    indx.y = indx_J97.float_value;
    indx.z = (362436.0f / 16777216.0f);
    indx.w = 0.0f;

    seedtable[GID + GID_SIZE * 97] = indx;   // (RM_I97,RM_J97,RM_C,0)
}

__attribute__((always_inline)) float4
rm_step(__global float4 * seedtable,uint* RM_I97,uint* RM_J97,float* uniz)
{
        float4 uni;
        uni = seedtable[GID + GID_SIZE * (*RM_I97)] - seedtable[GID + GID_SIZE * (*RM_J97)];
	    uni = select(uni, (uni + 1.0f), uni < (float4) 0.0f);
        seedtable[GID + GID_SIZE * (*RM_I97)] = uni;

	    if ((*RM_I97) == 0) (*RM_I97) = 97;
	    if ((*RM_J97) == 0) (*RM_J97) = 97;
	    (*RM_I97)--;
	    (*RM_J97)--;

        (*uniz) -= RM_CD;
	    if ((*uniz) < 0.0) {(*uniz) += RM_CM;}
        uni -= (*uniz);
	    uni = select(uni, (uni + 1.0f), uni < (float4) 0.0f);
        return uni;
}

#ifdef PRECISION_DOUBLE  // if double precision is defined
__attribute__((always_inline)) hgpu_double4
rm_step_double(__global float4 * seedtable,uint* RM_I97,uint* RM_J97,float* uniz)
{
    hgpu_double4 result;
    float4 rnd1, rnd2;
    rnd1 = rm_step(seedtable,RM_I97,RM_J97,uniz);
#ifndef PRNG_SKIP_CHECK
    bool flag = true;
    while (flag) {
#endif
        rnd2 = rm_step(seedtable,RM_I97,RM_J97,uniz);
        result = hgpu_float4_to_double4(rnd1,rnd2,RM_min,RM_max,RM_k);

#ifndef PRNG_SKIP_CHECK
        if ((result.x>=RM_left) && (result.x<RM_right) &&
            (result.y>=RM_left) && (result.y<RM_right) &&
            (result.z>=RM_left) && (result.z<RM_right) &&
            (result.w>=RM_left) && (result.w<RM_right))
            flag = false;
        else
            rnd1 = rnd2;
    }
#endif
    return result;
}
#endif

__kernel void
ranmar(__global float4 * seedtable,__global hgpu_float4 * prns, const uint samples)
{
    uint giddst = GID;
    float4 uni = (float4) 0.0;
    Uint_and_Float indx_I97, indx_J97;
    float4 indx = seedtable[GID + GID_SIZE * 97];
    indx_I97.float_value = indx.x;
    indx_J97.float_value = indx.y;
    uint RM_I97 = indx_I97.uint_value;
    uint RM_J97 = indx_J97.uint_value;
    float uniz = indx.z;
    for (uint i=0; i<samples; i++) {
#ifdef PRECISION_DOUBLE // if double precision is defined
        hgpu_double4 result = rm_step_double(seedtable,&RM_I97,&RM_J97,&uniz);
        prns[giddst] = result;
#else
        uni = rm_step(seedtable,&RM_I97,&RM_J97,&uniz);
        prns[giddst] = uni;
#endif
        giddst += GID_SIZE;
    }

    indx_I97.uint_value = RM_I97;
    indx_J97.uint_value = RM_J97;
    indx.z = uniz;
    indx.x = indx_I97.float_value;
    indx.y = indx_J97.float_value;
    seedtable[GID + GID_SIZE * 97] = indx;
}

#endif


restore LRN bwd wit out of rage check

restore LRN bwd wit out of rage check

/*
 * Copyright (c) 2015 AMD Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and/or associated documentation files (the
 * "Materials"), to deal in the Materials without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Materials, and to
 * permit persons to whom the Materials are furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Materials.
 *
 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
 */

#define _FLOAT					float
#define _FLOAT2					float2
#define _FLOAT4					float4
#define _FLOAT8					float8

#define MLO_LRN_GROUP_SZ2 1
#define MLO_LRN_STRIDE 1

#define MLO_LRN_LCL_DATA_WIDTH (MLO_LRN_GROUP_SZ0 *MLO_LRN_N_HORIZ_OUT_PIX + MLO_LRN_KERNEL_SZ - 1)
#define MLO_LRN_LCL_DATA_HEIGHT  (MLO_LRN_GROUP_SZ1 * MLO_LRN_N_VERT_OUT_PIX + MLO_LRN_KERNEL_SZ - 1)
#define MLO_LRN_GROUP_SZ (MLO_LRN_GROUP_SZ2 * MLO_LRN_GROUP_SZ1 * MLO_LRN_GROUP_SZ0)
//#define MLO_LRN_PREPAD_SZ (MLO_LRN_KERNEL_SZ - 1)/2

__attribute__((reqd_work_group_size(MLO_LRN_GROUP_SZ0,MLO_LRN_GROUP_SZ1,MLO_LRN_GROUP_SZ2)))
__kernel void MLOpenLRNWithinChannel(
       const __global _FLOAT * bot,
       __global _FLOAT * top,
#if MLO_LRN_DO_SCALE
	   __global _FLOAT * scale,
#endif
	   _FLOAT alphaoverarea,
	   _FLOAT alpha,
	   _FLOAT beta,
	   _FLOAT K
	   )
{

// IT's taken from POOLING AVE with stride = 1'
		__local _FLOAT bot_data[MLO_LRN_LCL_DATA_WIDTH * MLO_LRN_LCL_DATA_HEIGHT];
		int x = get_group_id(0) * MLO_LRN_GROUP_SZ0 * MLO_LRN_N_HORIZ_OUT_PIX;
		int y = get_group_id(1) * MLO_LRN_GROUP_SZ1 * MLO_LRN_N_VERT_OUT_PIX;
		int lcl_id0 = get_local_id(0);
		int lcl_id1 = get_local_id(1);
		int lcl_id = (lcl_id1 << MLO_LRN_GROUP_LG2SZ0) + lcl_id0;
		int ob = get_global_id(2); // output * batch_sz
		int o = ob / MLO_LRN_BATCH_SZ;
		int b = ob - o * MLO_LRN_BATCH_SZ;
		int bot_x = x;
		int bot_y = y;
		int bot_off = b * MLO_LRN_BOT_BATCH_STRIDE + o * MLO_LRN_BOT_CHANNEL_STRIDE;

		_FLOAT prv_scale[MLO_LRN_N_VERT_OUT_PIX][MLO_LRN_N_HORIZ_OUT_PIX];

// load tile
		for( int b_j = lcl_id1; b_j < MLO_LRN_LCL_DATA_HEIGHT; b_j += MLO_LRN_GROUP_SZ1)
		{
			int bot_y_act = bot_y + b_j - MLO_LRN_PAD;

			bool invisibleY = (bot_y_act < 0) || (bot_y_act >= MLO_LRN_BOT_HEIGHT);

			bot_y_act = (invisibleY) ? 0 : bot_y_act;

			int bot_y_off = bot_y_act * MLO_LRN_BOT_STRIDE;

			int lcl_off_v = b_j * MLO_LRN_LCL_DATA_WIDTH;

			for(int b_i = lcl_id0; b_i < MLO_LRN_LCL_DATA_WIDTH; b_i += MLO_LRN_GROUP_SZ0)
			{

				int bot_x_act = bot_x + b_i - MLO_LRN_PAD;

				bool invisibleX = (bot_x_act < 0) || (bot_x_act >= MLO_LRN_BOT_WIDTH);

				bot_x_act = (invisibleX) ? 0 : bot_x_act;

				_FLOAT bot_val = bot[bot_off + bot_y_off + bot_x_act];

				bot_val = (invisibleX || invisibleY)?
							0 :
							bot_val;

				bot_val = bot_val;

				bot_data[lcl_off_v + b_i] = bot_val;

			}
		}

		barrier(CLK_LOCAL_MEM_FENCE);

		int top_y = (y + lcl_id1 * MLO_LRN_N_VERT_OUT_PIX);
		int top_x = (x + lcl_id0 * MLO_LRN_N_HORIZ_OUT_PIX);

		int lcl_y = lcl_id1 * MLO_LRN_N_VERT_OUT_PIX;
		int lcl_x = lcl_id0 * MLO_LRN_N_HORIZ_OUT_PIX;
		int lcl_off = lcl_y * MLO_LRN_LCL_DATA_WIDTH + lcl_x;

		for( int k = 0; k < MLO_LRN_N_VERT_OUT_PIX; k++)
		{

			int hstart = y + lcl_id1 * MLO_LRN_N_VERT_OUT_PIX  + k - MLO_LRN_PAD;
			int hend = min(hstart + MLO_LRN_KERNEL_SZ, MLO_LRN_BOT_HEIGHT + MLO_LRN_PAD);

			for(int l = 0; l < MLO_LRN_N_HORIZ_OUT_PIX; l++)
			{

				int wstart = x + lcl_id0 * MLO_LRN_N_HORIZ_OUT_PIX + l - MLO_LRN_PAD;
				int wend = min(wstart + MLO_LRN_KERNEL_SZ, MLO_LRN_BOT_WIDTH + MLO_LRN_PAD);

				int adj_area_size = (hend - hstart) * (wend - wstart);

				_FLOAT accum = 0;
				for( int j = 0; j < MLO_LRN_KERNEL_SZ; j++)
				{
					for(int i = 0; i < MLO_LRN_KERNEL_SZ; i++)
					{

						_FLOAT bot_val =  bot_data[lcl_off + (k +j)*MLO_LRN_LCL_DATA_WIDTH + (l +i)];
						accum   += bot_val * bot_val;

					}
				}

				_FLOAT adj_alphaoverarea = alpha / adj_area_size;
				prv_scale[k][l]  = K + accum * adj_alphaoverarea ;

#if 0
				if ( top_x + l == 7 && top_y + k == 0 && o == 0)
				{
					printf("K:lrn: %13.11f %13.11f %13.11f\n", prv_scale[k][l], accum, adj_alphaoverarea);
				}
#endif
			}
		}

		int top_off = b * MLO_LRN_TOP_BATCH_STRIDE + o * MLO_LRN_TOP_CHANNEL_STRIDE + top_y * MLO_LRN_TOP_STRIDE + top_x;
		int scale_off = b * MLO_LRN_SCALE_BATCH_STRIDE + o * MLO_LRN_SCALE_CHANNEL_STRIDE + top_y * MLO_LRN_SCALE_STRIDE + top_x;

		for( int k = 0; k < MLO_LRN_N_VERT_OUT_PIX; k++)
		{
			for(int l = 0; l < MLO_LRN_N_HORIZ_OUT_PIX; l++)
			{
				_FLOAT s;
				_FLOAT bot_val;

				if (top_y + k < MLO_LRN_TOP_HEIGHT && top_x + l < MLO_LRN_TOP_WIDTH)
				{

					s = native_exp((_FLOAT)-beta * native_log(prv_scale[k][l]));
//					s = pow(prv_scale[k][l], -beta);
					bot_val =  bot_data[lcl_off + (k +MLO_LRN_PAD)*MLO_LRN_LCL_DATA_WIDTH + (l + MLO_LRN_PAD)];
#if MLO_LRN_DO_SCALE
					scale[scale_off + k * MLO_LRN_SCALE_STRIDE +l] = prv_scale[k][l];
#endif
					top[top_off + k * MLO_LRN_TOP_STRIDE +l] = bot_val * s;
				}
#if 0
				if ( top_x + l == 9 && top_y + k == 4 && o == 0)
				{
					printf("K:lrn: %13.11f %13.11f %13.11f %13.11f\n", top[top_off + k * MLO_LRN_TOP_STRIDE +l], bot_val, s, prv_scale[k][l]);
				}
#endif

			}
		}

}

__attribute__((reqd_work_group_size(MLO_LRN_GROUP_SZ0,MLO_LRN_GROUP_SZ1,MLO_LRN_GROUP_SZ2)))
__kernel void MLOpenLRNWithinChannelBwd(
       const __global _FLOAT * top,
	   const __global _FLOAT *	bot,
       const __global _FLOAT * top_df,
	   const __global _FLOAT *	scale,
       __global _FLOAT * bot_df,
	   _FLOAT ratio, //2. * alpha * beta / local_area
	   _FLOAT alpha,
	   _FLOAT beta
	   )
{
		__local _FLOAT top_df_data[MLO_LRN_LCL_DATA_WIDTH * MLO_LRN_LCL_DATA_HEIGHT];
		__local _FLOAT ratio_data[MLO_LRN_LCL_DATA_WIDTH * MLO_LRN_LCL_DATA_HEIGHT];
		int x = get_group_id(0) * MLO_LRN_GROUP_SZ0 * MLO_LRN_N_HORIZ_OUT_PIX;
		int y = get_group_id(1) * MLO_LRN_GROUP_SZ1 * MLO_LRN_N_VERT_OUT_PIX;
		int lcl_id0 = get_local_id(0);
		int lcl_id1 = get_local_id(1);
		int lcl_id = (lcl_id1 << MLO_LRN_GROUP_LG2SZ0) + lcl_id0;
		int ob = get_global_id(2); // output * batch_sz
		int o = ob / MLO_LRN_BATCH_SZ;
		int b = ob - o * MLO_LRN_BATCH_SZ;
		int top_x = x;
		int top_y = y;
		int top_df_off = b * MLO_LRN_TOPDF_BATCH_STRIDE + o * MLO_LRN_TOPDF_CHANNEL_STRIDE;
		int scale_off = b * MLO_LRN_SCALE_BATCH_STRIDE + o * MLO_LRN_SCALE_CHANNEL_STRIDE;
		int bot_x = x + lcl_id0 * MLO_LRN_N_HORIZ_OUT_PIX;
		int bot_y = y + lcl_id1 * MLO_LRN_N_VERT_OUT_PIX;

		_FLOAT prv_exp_scale[MLO_LRN_N_VERT_OUT_PIX][MLO_LRN_N_HORIZ_OUT_PIX];
//		_FLOAT prv_top_df[MLO_LRN_N_VERT_OUT_PIX][MLO_LRN_N_HORIZ_OUT_PIX];

		// load top_diff and scale tiles
		for( int b_j = lcl_id1; b_j < MLO_LRN_LCL_DATA_HEIGHT; b_j += MLO_LRN_GROUP_SZ1)
		{
			int top_y_act = top_y + b_j - MLO_LRN_PAD;

			bool invisibleY = (top_y_act < 0) || (top_y_act >= MLO_LRN_TOP_HEIGHT);

			top_y_act = (invisibleY) ? 0 : top_y_act;

			int top_df_y_off = top_y_act * MLO_LRN_TOPDF_STRIDE;
			int scale_y_off = top_y_act * MLO_LRN_SCALE_STRIDE;

			int lcl_off_v = b_j * MLO_LRN_LCL_DATA_WIDTH;

			for(int b_i = lcl_id0; b_i < MLO_LRN_LCL_DATA_WIDTH; b_i += MLO_LRN_GROUP_SZ0)
			{

				int top_x_act = top_x + b_i - MLO_LRN_PAD;

				bool invisibleX = (top_x_act < 0) || (top_x_act >= MLO_LRN_TOP_WIDTH);

				top_x_act = (invisibleX) ? 0 : top_x_act;

				_FLOAT top_df_val = top_df[top_df_off + top_df_y_off + top_x_act];
				_FLOAT scale_val = scale[scale_off + scale_y_off + top_x_act];

				top_df_val = (invisibleX || invisibleY)?
							0 :
							top_df_val;
				scale_val = (invisibleX || invisibleY)?
							1.f :
							scale_val;

				top_df_data[lcl_off_v + b_i] = top_df_val;
				ratio_data[lcl_off_v + b_i] = scale_val;

			}
		}

		barrier(CLK_LOCAL_MEM_FENCE);

		// actual top_diffs and scales
		for(int j = 0; j < MLO_LRN_N_VERT_OUT_PIX; ++j)
		{
			int lcl_off_v = (lcl_id1 * MLO_LRN_N_VERT_OUT_PIX + MLO_LRN_PAD + j) *  MLO_LRN_LCL_DATA_WIDTH;
			for(int i = 0; i < MLO_LRN_N_HORIZ_OUT_PIX; i++)
			{
				_FLOAT scale = ratio_data[lcl_off_v + lcl_id0 * MLO_LRN_N_HORIZ_OUT_PIX + MLO_LRN_PAD + i];
				prv_exp_scale[j][i]= native_exp(-beta * native_log(scale));
//				prv_exp_scale[j][i]= pow(scale, -beta);
#if 0
				if (o==0 && b==0 && (bot_x + i) ==2 && (bot_y + j) == 0)
				{
					printf("K:scl: %d %d  %11.9f %11.9f %11.9f\n",
					i, j,
					prv_exp_scale[j][i],
					beta, scale
					);
				}
#endif

//				_FLOAT top_df_val = top_df_data[lcl_off_v + lcl_id0 * MLO_LRN_N_HORIZ_OUT_PIX + MLO_LRN_PAD + i];
//				prv_top_df[j][i] = top_df_val;
			}
		}

// read top and load ratio tile
		int top_off = b * MLO_LRN_TOP_BATCH_STRIDE + o * MLO_LRN_TOP_CHANNEL_STRIDE;
		for( int b_j = lcl_id1; b_j < MLO_LRN_LCL_DATA_HEIGHT; b_j += MLO_LRN_GROUP_SZ1)
		{
			int top_y_act = top_y + b_j - MLO_LRN_PAD;

			bool invisibleY = (top_y_act < 0) || (top_y_act >= MLO_LRN_TOP_HEIGHT);

			top_y_act = (invisibleY) ? 0 : top_y_act;

			int top_y_off = top_y_act * MLO_LRN_TOP_STRIDE;

			int lcl_off_v = b_j * MLO_LRN_LCL_DATA_WIDTH;

			for(int b_i = lcl_id0; b_i < MLO_LRN_LCL_DATA_WIDTH; b_i += MLO_LRN_GROUP_SZ0)
			{

				int top_x_act = top_x + b_i - MLO_LRN_PAD;

				bool invisibleX = (top_x_act < 0) || (top_x_act >= MLO_LRN_TOP_WIDTH);

				top_x_act = (invisibleX) ? 0 : top_x_act;

				_FLOAT top_val = top[top_off + top_y_off + top_x_act];

				top_val = (invisibleX || invisibleY) ? 0 : top_val;

				_FLOAT top_df_val = top_df_data[lcl_off_v + b_i];

				_FLOAT scale_val = ratio_data[lcl_off_v + b_i];

	// scale val is not 0
				_FLOAT 	ratio_dta =
						(top_df_val * top_val) / scale_val;
#if 0
				if (o==0 && b==0 && (b_i >=0 && b_i < 8) && (b_j == 0))
				{
					printf("K:rdt: %d %d  %11.9f %11.9f %11.9f %11.9f\n",
					b_i, b_j,
					top_df_val, top_val,scale_val,
					ratio_dta
					);
				}
#endif
	// replacing scale with ratio
				ratio_data[lcl_off_v + b_i] = ratio_dta;

			}
		}

		barrier(CLK_LOCAL_MEM_FENCE);

// caculate bot diff
		_FLOAT prv_bot_diff[MLO_LRN_N_VERT_OUT_PIX][MLO_LRN_N_HORIZ_OUT_PIX];

		for(int j = 0; j < MLO_LRN_N_VERT_OUT_PIX; ++j)
		{
			int v_off_v =  (lcl_id1 * MLO_LRN_N_VERT_OUT_PIX + j);
			int hstart = y + v_off_v - MLO_LRN_PAD;
			int hend = min(hstart + MLO_LRN_KERNEL_SZ, MLO_LRN_TOP_HEIGHT + MLO_LRN_PAD);

		// accum offset, vertical
//			int lcl_a_off_v = v_off_v *  MLO_LRN_LCL_DATA_WIDTH;
		// value offset, vertical
			int lcl_v_off_v = (v_off_v + MLO_LRN_PAD) *  MLO_LRN_LCL_DATA_WIDTH;
			for(int i = 0; i < MLO_LRN_N_HORIZ_OUT_PIX; i++)
			{
				_FLOAT prv_ratio_accum = 0;
				int v_off_h = lcl_id0 * MLO_LRN_N_HORIZ_OUT_PIX + i;

				int wstart = x + v_off_h - MLO_LRN_PAD;
				int wend = min(wstart + MLO_LRN_KERNEL_SZ, MLO_LRN_TOP_WIDTH + MLO_LRN_PAD);

				int adj_area_size = (hend - hstart) * (wend - wstart);

		// accum offset, horiz
				int lcl_a_off_h = v_off_h;
		//	value offset, horiz
				int lcl_v_off_h = lcl_a_off_h  + MLO_LRN_PAD;

				for(int k = 0; k < MLO_LRN_KERNEL_SZ; k++)
				{
					for(int l = 0; l < MLO_LRN_KERNEL_SZ; l++)
					{
						prv_ratio_accum += ratio_data[(v_off_v + k) * MLO_LRN_LCL_DATA_WIDTH + lcl_a_off_h + l];
#if 0
				if (o==0 && b==0 && (bot_x + i) ==2 && (bot_y + j) == 0)
				{
					printf("K:prv: %d %d  %d %d  %11.9f %11.9f\n",
					l, k,
					(v_off_v + k) * MLO_LRN_LCL_DATA_WIDTH + lcl_a_off_h + l,
					MLO_LRN_LCL_DATA_WIDTH * MLO_LRN_LCL_DATA_HEIGHT,
					prv_ratio_accum,
					ratio_data[(v_off_v + k)  * MLO_LRN_LCL_DATA_WIDTH + lcl_a_off_h + l]
					);
				}
#endif

					}
				}

				_FLOAT top_df_val = top_df_data[lcl_v_off_v + lcl_v_off_h];
				_FLOAT bot_dta = bot[MLO_LRN_BOT_BATCH_STRIDE * b + MLO_LRN_BOT_CHANNEL_STRIDE *o + MLO_LRN_BOT_STRIDE * (y + v_off_v) + x + v_off_h];
				_FLOAT adj_ratio = 2.f * alpha * beta / adj_area_size;
				_FLOAT prv_accum_ratio =
					adj_ratio * bot_dta * prv_ratio_accum;
				prv_bot_diff[j][i] =
					prv_exp_scale[j][i] * top_df_val - prv_accum_ratio;
#if 0
				if (o==0 && b==0 && (bot_x + i) ==2 && (bot_y + j) == 0)
				{
					printf("K:lrn: %11.9f %11.9f %11.9f\n%11.9f %11.9f %11.9f\n%11.9f\n",
					adj_ratio, bot_dta, prv_ratio_accum,
					prv_exp_scale[j][i], top_df_val, prv_accum_ratio,
					prv_bot_diff[j][i]
					);
				}
#endif
			}
		}

		for( int j = 0; j < MLO_LRN_N_VERT_OUT_PIX; j++)
		{
			for(int i = 0; i < MLO_LRN_N_HORIZ_OUT_PIX; i++)
			{
				if (bot_y + j < MLO_LRN_BOT_HEIGHT && bot_x + i < MLO_LRN_BOT_WIDTH)
				{

					bot_df[MLO_LRN_BOTDF_BATCH_STRIDE * b + MLO_LRN_BOTDF_CHANNEL_STRIDE *o + MLO_LRN_BOTDF_STRIDE * (bot_y + j) + bot_x + i] = prv_bot_diff[j][i];
				}
			}
		}

}

#if (MLO_LRN_N_INPUTS + 2* MLO_LRN_PAD - 1 < MLO_LRN_KERNEL_SZ || MLO_LRN_N_OUTPUTSS + 2* MLO_LRN_PAD - 1 < MLO_LRN_KERNEL_SZ)
#define MLO_LOW_CHNL_COUNT 1
#else
#define MLO_LOW_CHNL_COUNT 0
#endif
__attribute__((reqd_work_group_size(MLO_LRN_GROUP_SZ0,MLO_LRN_GROUP_SZ1,MLO_LRN_GROUP_SZ2)))
__kernel void MLOpenLRNAcrossChannels1(
       const __global _FLOAT * bottom,
       __global _FLOAT * top,
#if MLO_LRN_DO_SCALE
	   __global _FLOAT *scale,
#endif
	   _FLOAT alphaoverarea,
	   _FLOAT alpha,
	   _FLOAT beta,
	   _FLOAT K
	   )
{

		int x = get_global_id(0); // channel x
		int y = get_global_id(1); // channel y
		int b = get_global_id(2); // batch
		_FLOAT accum = 0;
		_FLOAT bot_in[MLO_LRN_KERNEL_SZ];
		_FLOAT bot_in2[MLO_LRN_KERNEL_SZ];
		int c_i = 0, c_o = 0;

		int top_off = 0;
		int scale_off = 0;

		for( c_i = 0; c_i < MLO_LRN_PAD; c_i++)
		{
			_FLOAT bot_val = bottom[MLO_LRN_BOT_BATCH_STRIDE * b + MLO_LRN_BOT_CHANNEL_STRIDE *c_i + MLO_LRN_BOT_STRIDE * y + x];
#if MLO_LOW_CHNL_COUNT
			bot_in[c_i] = (c_i < MLO_LRN_N_INPUTS) ? bot_val : 0;
#endif
			bot_in2[c_i] = bot_in[c_i] * bot_in[c_i];
			accum =
				accum + bot_in2[c_i];
//				fma(bot_in[c_i + MLO_LRN_PAD], bot_in[c_i + MLO_LRN_PAD], accum);

		}

		for( ; c_i < MLO_LRN_KERNEL_SZ; c_i++, c_o++)
		{
			_FLOAT bot_val = bottom[MLO_LRN_BOT_BATCH_STRIDE * b + MLO_LRN_BOT_CHANNEL_STRIDE *c_i + MLO_LRN_BOT_STRIDE * y + x];

#if MLO_LOW_CHNL_COUNT
			bot_in[c_i] = (c_i < MLO_LRN_N_INPUTS) ? bot_val : 0;
#endif
			bot_in2[c_i] = bot_in[c_i] * bot_in[c_i];
			accum =
				accum + bot_in2[c_i];

			top_off = b * MLO_LRN_TOP_BATCH_STRIDE + c_o * MLO_LRN_TOP_CHANNEL_STRIDE + y * MLO_LRN_TOP_STRIDE +x;
			scale_off = b * MLO_LRN_SCALE_BATCH_STRIDE + c_o * MLO_LRN_SCALE_CHANNEL_STRIDE + y * MLO_LRN_SCALE_STRIDE +x;
			_FLOAT prv_scale =
				(K + accum * alphaoverarea);
//				fma(accum,alphaoverarea, 1.f);

			_FLOAT exp_scale =
				native_exp(-beta * native_log(prv_scale));
//				pow(prv_scale,-beta);

			_FLOAT out_val = bot_in[c_o] * exp_scale;
#if MLO_LOW_CHNL_COUNT
			if (c_o < MLO_LRN_N_OUTPUTS)
#endif
			{
#if MLO_LRN_DO_SCALE
				scale[scale_off] = prv_scale;
#endif
				top[top_off] = out_val;
			}
		}

		for( ; c_i < MLO_LRN_N_CHANNELS; c_i++, c_o++)
		{

			_FLOAT prv_bot_in = bottom[MLO_LRN_BOT_BATCH_STRIDE * b + MLO_LRN_BOT_CHANNEL_STRIDE *c_i + MLO_LRN_BOT_STRIDE * y + x];
#if MLO_LOW_CHNL_COUNT
			prv_bot_in = (c_i < MLO_LRN_N_INPUTS) ? prv_bot_in : 0;
#endif
			_FLOAT prv_bot_in2 = prv_bot_in * prv_bot_in;
			accum =
				accum + prv_bot_in2;

			accum =
				accum - bot_in2[0];
//				fma(-bot_in[0], bot_in[0], accum);

			for( int i = 0; i < MLO_LRN_KERNEL_SZ - 1; i++)
			{
				bot_in[i] = bot_in[i+1];
				bot_in2[i] = bot_in2[i+1];
			}

			bot_in[MLO_LRN_KERNEL_SZ - 1] = prv_bot_in;
			bot_in2[MLO_LRN_KERNEL_SZ - 1] = prv_bot_in2;

			top_off = b * MLO_LRN_TOP_BATCH_STRIDE + c_o * MLO_LRN_TOP_CHANNEL_STRIDE + y * MLO_LRN_TOP_STRIDE +x;
			scale_off = b * MLO_LRN_SCALE_BATCH_STRIDE + c_o * MLO_LRN_SCALE_CHANNEL_STRIDE + y * MLO_LRN_SCALE_STRIDE +x;
			_FLOAT prv_scale =
				(K + accum * alphaoverarea);
//				fma(accum,alphaoverarea, 1.f);

			_FLOAT exp_scale =
				native_exp(-beta * native_log(prv_scale));
//				pow(prv_scale,-beta);

			_FLOAT out_val = bot_in[MLO_LRN_PAD] * exp_scale;
#if MLO_LOW_CHNL_COUNT
			if (c_o < MLO_LRN_N_OUTPUTS)
#endif
			{
#if MLO_LRN_DO_SCALE
				scale[scale_off] = prv_scale;
#endif
				top[top_off] = out_val;
			}

		}

		for(  ; c_i < MLO_LRN_N_CHANNELS + MLO_LRN_PAD; c_i++, c_o++)
		{

			accum =
				accum - bot_in2[0];
//				fma(-bot_in[0], bot_in[0], accum);

			for( int i = 0; i < MLO_LRN_KERNEL_SZ - 1; i++)
			{
				bot_in[i] = bot_in[i+1];
				bot_in2[i] = bot_in2[i+1];
			}

			top_off = b * MLO_LRN_TOP_BATCH_STRIDE + c_o * MLO_LRN_TOP_CHANNEL_STRIDE + y * MLO_LRN_TOP_STRIDE + x;
			scale_off = b * MLO_LRN_SCALE_BATCH_STRIDE + c_o * MLO_LRN_SCALE_CHANNEL_STRIDE + y * MLO_LRN_SCALE_STRIDE +x;

			_FLOAT prv_scale =
				(K + accum * alphaoverarea);
//				fma(accum,alphaoverarea, 1.f);

			_FLOAT exp_scale =
				native_exp(-beta * native_log(prv_scale));
	//			pow(prv_scale,-beta);

			_FLOAT out_val = bot_in[MLO_LRN_PAD] * exp_scale;
#if MLO_LOW_CHNL_COUNT
			if (c_o < MLO_LRN_N_OUTPUTS)
#endif
			{
#if MLO_LRN_DO_SCALE
				scale[scale_off] = prv_scale;
#endif
				top[top_off] = out_val;
			}
		}

}

__attribute__((reqd_work_group_size(MLO_LRN_GROUP_SZ0,MLO_LRN_GROUP_SZ1,MLO_LRN_GROUP_SZ2)))
__kernel void MLOpenLRNAcrossChannelsBwd1(
       const __global _FLOAT * top,
	   const __global _FLOAT *	bot,
       const __global _FLOAT * top_df,
	   const __global _FLOAT *	scale,
       __global _FLOAT * bot_df,
	   _FLOAT ratio, //2. * alpha * beta / local_area
	   _FLOAT alpha,
	   _FLOAT beta
	   )
{

		int x = get_global_id(0); // channel x
		int y = get_global_id(1); // channel y
		int b = get_global_id(2); // batch
		_FLOAT accum_ratio = 0;
		_FLOAT top_df_in[MLO_LRN_KERNEL_SZ];
		_FLOAT scale_in[MLO_LRN_KERNEL_SZ];
		_FLOAT ratio_dta[MLO_LRN_KERNEL_SZ];
		int c_i = 0, c_o = 0;
		int bot_df_off = 0;

		for( c_i = 0; c_i < MLO_LRN_PAD; c_i++)
		{

			top_df_in[c_i] = top_df[MLO_LRN_TOPDF_BATCH_STRIDE * b + MLO_LRN_TOPDF_CHANNEL_STRIDE *c_i + MLO_LRN_TOPDF_STRIDE * y + x];
			scale_in[c_i] = scale[MLO_LRN_SCALE_BATCH_STRIDE * b + MLO_LRN_SCALE_CHANNEL_STRIDE * c_i + MLO_LRN_SCALE_STRIDE * y + x];
			_FLOAT top_dta = top[MLO_LRN_TOP_BATCH_STRIDE *b  + MLO_LRN_TOP_CHANNEL_STRIDE * c_i + MLO_LRN_TOP_STRIDE * y + x];

			ratio_dta[c_i] = (top_df_in[c_i] * top_dta) / scale_in[c_i];

#if MLO_LOW_CHNL_COUNT
			ratio_dta[c_i] = (c_i < MLO_LRN_N_OUTPUTS) ? ratio_dta[c_i] : 0;
#endif
#if 0
			if ( x == 5 && y == 11/* && c_o==12 */&& b==10)
			{
				printf("K:a %d %f %f\n",
					c_i,
					accum_ratio,
					ratio_dta[c_i]

				);

			}

#endif

 			accum_ratio =
				accum_ratio + ratio_dta[c_i] ;

		}

		for( ; c_i < MLO_LRN_KERNEL_SZ; c_i++, c_o++)
		{
			top_df_in[c_i] = top_df[MLO_LRN_TOPDF_BATCH_STRIDE * b + MLO_LRN_TOPDF_CHANNEL_STRIDE *c_i + MLO_LRN_TOPDF_STRIDE * y + x];
			scale_in[c_i] = scale[MLO_LRN_SCALE_BATCH_STRIDE * b + MLO_LRN_SCALE_CHANNEL_STRIDE * c_i + MLO_LRN_SCALE_STRIDE * y + x];
			_FLOAT top_dta = top[MLO_LRN_TOP_BATCH_STRIDE *b  + MLO_LRN_TOP_CHANNEL_STRIDE * c_i + MLO_LRN_TOP_STRIDE * y + x];
			ratio_dta[c_i] = (top_df_in[c_i] * top_dta) / scale_in[c_i];
#if MLO_LOW_CHNL_COUNT
			ratio_dta[c_i] = (c_i < MLO_LRN_N_OUTPUTS) ? ratio_dta[c_i] : 0;
#endif

#if 0
			if ( x == 5 && y == 11/* && c_o==12 */&& b==10)
			{
				printf("K:a %d %f %f\n",
					c_i,
					accum_ratio,
					ratio_dta[c_i]

				);

			}

#endif

 			accum_ratio =
				accum_ratio + ratio_dta[c_i] ;
#if MLO_LOW_CHNL_COUNT
			if (c_o < MLO_LRN_N_INPUTS)
#endif
			{
				_FLOAT bot_dta = bot[MLO_LRN_BOT_BATCH_STRIDE * b + MLO_LRN_BOT_CHANNEL_STRIDE *c_o + MLO_LRN_BOT_STRIDE * y + x];

				_FLOAT prv_scale = scale_in[c_o];

				_FLOAT exp_scale =
					native_exp(-beta * native_log(prv_scale));
//					pow(prv_scale, -beta);

				_FLOAT prv_accum_ratio =
					ratio * bot_dta * accum_ratio;

				_FLOAT out_val = top_df_in[c_o] * exp_scale - prv_accum_ratio;

				bot_df_off = MLO_LRN_BOTDF_BATCH_STRIDE * b + MLO_LRN_BOTDF_CHANNEL_STRIDE * c_o + MLO_LRN_BOTDF_STRIDE * y + x;

				bot_df[bot_df_off] = out_val;
			}

		}

		for( ; c_i < MLO_LRN_N_CHANNELS; c_i++, c_o++)
		{

			_FLOAT prv_top_df_in = top_df[MLO_LRN_TOPDF_BATCH_STRIDE * b + MLO_LRN_TOPDF_CHANNEL_STRIDE *c_i + MLO_LRN_TOPDF_STRIDE * y + x];
			_FLOAT prv_scale_in = scale[MLO_LRN_SCALE_BATCH_STRIDE * b + MLO_LRN_SCALE_CHANNEL_STRIDE * c_i + MLO_LRN_SCALE_STRIDE * y + x];
			_FLOAT top_dta = top[MLO_LRN_TOP_BATCH_STRIDE *b  + MLO_LRN_TOP_CHANNEL_STRIDE * c_i + MLO_LRN_TOP_STRIDE * y + x];
			_FLOAT prv_ratio_dta = prv_top_df_in * top_dta / prv_scale_in;
#if MLO_LOW_CHNL_COUNT
			prv_ratio_dta = (c_i < MLO_LRN_N_OUTPUTS) ? prv_ratio_dta : 0;
#endif

#if 0
			if ( x == 5 && y == 11/* && c_o==12 */&& b==10)
			{
				printf("K:a %d %f %f\n",
					c_i,
					accum_ratio,
					prv_ratio_dta

				);

			}

#endif

 			accum_ratio =
				accum_ratio + prv_ratio_dta ;

			accum_ratio =
				accum_ratio - ratio_dta[0];

			for( int i = 0; i < MLO_LRN_KERNEL_SZ - 1; i++)
			{
				top_df_in[i] = top_df_in[i+1];
				scale_in[i] = scale_in[i+1];
				ratio_dta[i] = ratio_dta[i+1];
			}

			top_df_in[MLO_LRN_KERNEL_SZ - 1] = prv_top_df_in;
			scale_in[MLO_LRN_KERNEL_SZ - 1] = prv_scale_in;
			ratio_dta[MLO_LRN_KERNEL_SZ - 1]= prv_ratio_dta;

#if 0
			if ( x == 3 && y == 0/* && c_o==12 */&& b==3)
			{
				printf("K: %d %16.12f %16.12f %16.12f %16.12f %16.12f\n",
					c_i,
					accum_ratio,
					prv_ratio_dta,
					prv_top_df_in,
					top_dta,
					prv_scale_in
				);

			}

#endif

#if MLO_LOW_CHNL_COUNT
			if (c_o < MLO_LRN_N_INPUTS)
#endif
			{
				_FLOAT bot_dta = bot[MLO_LRN_BOT_BATCH_STRIDE * b + MLO_LRN_BOT_CHANNEL_STRIDE *c_o + MLO_LRN_BOT_STRIDE * y + x];

				_FLOAT prv_scale = scale_in[MLO_LRN_PAD];

				_FLOAT exp_scale =
					native_exp(-beta * native_log(prv_scale));
				//				pow(prv_scale,-beta);

				_FLOAT prv_accum_ratio =
					ratio * bot_dta * accum_ratio;

				_FLOAT out_val = top_df_in[MLO_LRN_PAD] * exp_scale - prv_accum_ratio;

				bot_df_off = MLO_LRN_BOTDF_BATCH_STRIDE * b + MLO_LRN_BOTDF_CHANNEL_STRIDE * c_o + MLO_LRN_BOTDF_STRIDE * y + x;

				bot_df[bot_df_off] = out_val;
			}

		}

		for (; c_i < MLO_LRN_N_CHANNELS + MLO_LRN_PAD; c_i++, c_o++)
		{

			accum_ratio =
				accum_ratio - ratio_dta[0];

			for (int i = 0; i < MLO_LRN_KERNEL_SZ - 1; i++)
			{
				top_df_in[i] = top_df_in[i + 1];
				scale_in[i] = scale_in[i + 1];
				ratio_dta[i] = ratio_dta[i + 1];

			}

#if MLO_LOW_CHNL_COUNT
			if (c_o < MLO_LRN_N_INPUTS)
#endif
			{
				_FLOAT bot_dta = bot[MLO_LRN_BOT_BATCH_STRIDE * b + MLO_LRN_BOT_CHANNEL_STRIDE *c_o + MLO_LRN_BOT_STRIDE * y + x];

				_FLOAT prv_scale = scale_in[MLO_LRN_PAD];

				_FLOAT exp_scale =
					native_exp(-beta * native_log(prv_scale));
				//				pow(prv_scale,-beta);

				_FLOAT prv_accum_ratio =
					ratio * bot_dta * accum_ratio;

				_FLOAT out_val = top_df_in[MLO_LRN_PAD] * exp_scale - prv_accum_ratio;

				bot_df_off = MLO_LRN_BOTDF_BATCH_STRIDE * b + MLO_LRN_BOTDF_CHANNEL_STRIDE * c_o + MLO_LRN_BOTDF_STRIDE * y + x;

				bot_df[bot_df_off] = out_val;

#if 0
				if ( x == 5 && y == 11/* && c_o==12 */&& b== 10)
				{
					printf("K: %d %10.8f %10.8f %10.8f %10.8f %10.8f %10.8f %10.8f\n",
						c_i,
						bot_df[bot_df_off],
						top_df_in[MLO_LRN_PAD],
						exp_scale,
						prv_scale,
						-prv_accum_ratio,
						bot_dta,
						accum_ratio
						);

				}

#endif
			}
		}

}

/*
 * Copyright (c) 2015 AMD Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and/or associated documentation files (the
 * "Materials"), to deal in the Materials without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Materials, and to
 * permit persons to whom the Materials are furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Materials.
 *
 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
 */

#define _FLOAT					float
#define _FLOAT2					float2
#define _FLOAT4					float4
#define _FLOAT8					float8

#define MLO_LRN_GROUP_SZ2 1
#define MLO_LRN_STRIDE 1

#define MLO_LRN_LCL_DATA_WIDTH (MLO_LRN_GROUP_SZ0 *MLO_LRN_N_HORIZ_OUT_PIX + MLO_LRN_KERNEL_SZ - 1)
#define MLO_LRN_LCL_DATA_HEIGHT  (MLO_LRN_GROUP_SZ1 * MLO_LRN_N_VERT_OUT_PIX + MLO_LRN_KERNEL_SZ - 1)
#define MLO_LRN_GROUP_SZ (MLO_LRN_GROUP_SZ2 * MLO_LRN_GROUP_SZ1 * MLO_LRN_GROUP_SZ0)
//#define MLO_LRN_PREPAD_SZ (MLO_LRN_KERNEL_SZ - 1)/2

__attribute__((reqd_work_group_size(MLO_LRN_GROUP_SZ0,MLO_LRN_GROUP_SZ1,MLO_LRN_GROUP_SZ2)))
__kernel void MLOpenLRNWithinChannel(
       const __global _FLOAT * bot,
       __global _FLOAT * top,
#if MLO_LRN_DO_SCALE
	   __global _FLOAT * scale,
#endif
	   _FLOAT alphaoverarea,
	   _FLOAT alpha,
	   _FLOAT beta,
	   _FLOAT K
	   )
{

// IT's taken from POOLING AVE with stride = 1'
		__local _FLOAT bot_data[MLO_LRN_LCL_DATA_WIDTH * MLO_LRN_LCL_DATA_HEIGHT];
		int x = get_group_id(0) * MLO_LRN_GROUP_SZ0 * MLO_LRN_N_HORIZ_OUT_PIX;
		int y = get_group_id(1) * MLO_LRN_GROUP_SZ1 * MLO_LRN_N_VERT_OUT_PIX;
		int lcl_id0 = get_local_id(0);
		int lcl_id1 = get_local_id(1);
		int lcl_id = (lcl_id1 << MLO_LRN_GROUP_LG2SZ0) + lcl_id0;
		int ob = get_global_id(2); // output * batch_sz
		int o = ob / MLO_LRN_BATCH_SZ;
		int b = ob - o * MLO_LRN_BATCH_SZ;
		int bot_x = x;
		int bot_y = y;
		int bot_off = b * MLO_LRN_BOT_BATCH_STRIDE + o * MLO_LRN_BOT_CHANNEL_STRIDE;

		_FLOAT prv_scale[MLO_LRN_N_VERT_OUT_PIX][MLO_LRN_N_HORIZ_OUT_PIX];

// load tile
		for( int b_j = lcl_id1; b_j < MLO_LRN_LCL_DATA_HEIGHT; b_j += MLO_LRN_GROUP_SZ1)
		{
			int bot_y_act = bot_y + b_j - MLO_LRN_PAD;

			bool invisibleY = (bot_y_act < 0) || (bot_y_act >= MLO_LRN_BOT_HEIGHT);

			bot_y_act = (bot_y_act < 0) ? 0 : (bot_y_act >= MLO_LRN_BOT_HEIGHT) ? MLO_LRN_BOT_HEIGHT - 1: bot_y_act;

			int bot_y_off = bot_y_act * MLO_LRN_BOT_STRIDE;

			int lcl_off_v = b_j * MLO_LRN_LCL_DATA_WIDTH;

			for(int b_i = lcl_id0; b_i < MLO_LRN_LCL_DATA_WIDTH; b_i += MLO_LRN_GROUP_SZ0)
			{

				int bot_x_act = bot_x + b_i - MLO_LRN_PAD;

				bool invisibleX = (bot_x_act < 0) || (bot_x_act >= MLO_LRN_BOT_WIDTH);

				bot_x_act = (bot_x_act < 0) ? 0 : (bot_x_act >= MLO_LRN_BOT_WIDTH) ? MLO_LRN_BOT_WIDTH - 1: bot_x_act;

				_FLOAT bot_val = bot[bot_off + bot_y_off + bot_x_act];

				bot_val = (invisibleX || invisibleY)?
							0 :
							bot_val;

				bot_val = bot_val;

				bot_data[lcl_off_v + b_i] = bot_val;

			}
		}

		barrier(CLK_LOCAL_MEM_FENCE);

		int top_y = (y + lcl_id1 * MLO_LRN_N_VERT_OUT_PIX);
		int top_x = (x + lcl_id0 * MLO_LRN_N_HORIZ_OUT_PIX);

		int lcl_y = lcl_id1 * MLO_LRN_N_VERT_OUT_PIX;
		int lcl_x = lcl_id0 * MLO_LRN_N_HORIZ_OUT_PIX;
		int lcl_off = lcl_y * MLO_LRN_LCL_DATA_WIDTH + lcl_x;

		for( int k = 0; k < MLO_LRN_N_VERT_OUT_PIX; k++)
		{

			int hstart = y + lcl_id1 * MLO_LRN_N_VERT_OUT_PIX  + k - MLO_LRN_PAD;
			int hend = min(hstart + MLO_LRN_KERNEL_SZ, MLO_LRN_BOT_HEIGHT + MLO_LRN_PAD);

			for(int l = 0; l < MLO_LRN_N_HORIZ_OUT_PIX; l++)
			{

				int wstart = x + lcl_id0 * MLO_LRN_N_HORIZ_OUT_PIX + l - MLO_LRN_PAD;
				int wend = min(wstart + MLO_LRN_KERNEL_SZ, MLO_LRN_BOT_WIDTH + MLO_LRN_PAD);

				int adj_area_size = (hend - hstart) * (wend - wstart);

				_FLOAT accum = 0;
				for( int j = 0; j < MLO_LRN_KERNEL_SZ; j++)
				{
					for(int i = 0; i < MLO_LRN_KERNEL_SZ; i++)
					{

						_FLOAT bot_val =  bot_data[lcl_off + (k +j)*MLO_LRN_LCL_DATA_WIDTH + (l +i)];
						accum   += bot_val * bot_val;

					}
				}

				_FLOAT adj_alphaoverarea = alpha / adj_area_size;
				prv_scale[k][l]  = K + accum * adj_alphaoverarea ;

#if 0
				if ( top_x + l == 7 && top_y + k == 0 && o == 0)
				{
					printf("K:lrn: %13.11f %13.11f %13.11f\n", prv_scale[k][l], accum, adj_alphaoverarea);
				}
#endif
			}
		}

		int top_off = b * MLO_LRN_TOP_BATCH_STRIDE + o * MLO_LRN_TOP_CHANNEL_STRIDE + top_y * MLO_LRN_TOP_STRIDE + top_x;
		int scale_off = b * MLO_LRN_SCALE_BATCH_STRIDE + o * MLO_LRN_SCALE_CHANNEL_STRIDE + top_y * MLO_LRN_SCALE_STRIDE + top_x;

		for( int k = 0; k < MLO_LRN_N_VERT_OUT_PIX; k++)
		{
			for(int l = 0; l < MLO_LRN_N_HORIZ_OUT_PIX; l++)
			{
				_FLOAT s;
				_FLOAT bot_val;

				if (top_y + k < MLO_LRN_TOP_HEIGHT && top_x + l < MLO_LRN_TOP_WIDTH)
				{

					s = native_exp((_FLOAT)-beta * native_log(prv_scale[k][l]));
//					s = pow(prv_scale[k][l], -beta);
					bot_val =  bot_data[lcl_off + (k +MLO_LRN_PAD)*MLO_LRN_LCL_DATA_WIDTH + (l + MLO_LRN_PAD)];
#if MLO_LRN_DO_SCALE
					scale[scale_off + k * MLO_LRN_SCALE_STRIDE +l] = prv_scale[k][l];
#endif
					top[top_off + k * MLO_LRN_TOP_STRIDE +l] = bot_val * s;
				}
#if 0
				if ( top_x + l == 9 && top_y + k == 4 && o == 0)
				{
					printf("K:lrn: %13.11f %13.11f %13.11f %13.11f\n", top[top_off + k * MLO_LRN_TOP_STRIDE +l], bot_val, s, prv_scale[k][l]);
				}
#endif

			}
		}

}

__attribute__((reqd_work_group_size(MLO_LRN_GROUP_SZ0,MLO_LRN_GROUP_SZ1,MLO_LRN_GROUP_SZ2)))
__kernel void MLOpenLRNWithinChannelBwd(
       const __global _FLOAT * top,
	   const __global _FLOAT *	bot,
       const __global _FLOAT * top_df,
	   const __global _FLOAT *	scale,
       __global _FLOAT * bot_df,
	   _FLOAT ratio, //2. * alpha * beta / local_area
	   _FLOAT alpha,
	   _FLOAT beta
	   )
{
		__local _FLOAT top_df_data[MLO_LRN_LCL_DATA_WIDTH * MLO_LRN_LCL_DATA_HEIGHT];
		__local _FLOAT ratio_data[MLO_LRN_LCL_DATA_WIDTH * MLO_LRN_LCL_DATA_HEIGHT];
		int x = get_group_id(0) * MLO_LRN_GROUP_SZ0 * MLO_LRN_N_HORIZ_OUT_PIX;
		int y = get_group_id(1) * MLO_LRN_GROUP_SZ1 * MLO_LRN_N_VERT_OUT_PIX;
		int lcl_id0 = get_local_id(0);
		int lcl_id1 = get_local_id(1);
		int lcl_id = (lcl_id1 << MLO_LRN_GROUP_LG2SZ0) + lcl_id0;
		int ob = get_global_id(2); // output * batch_sz
		int o = ob / MLO_LRN_BATCH_SZ;
		int b = ob - o * MLO_LRN_BATCH_SZ;
		int top_x = x;
		int top_y = y;
		int top_df_off = b * MLO_LRN_TOPDF_BATCH_STRIDE + o * MLO_LRN_TOPDF_CHANNEL_STRIDE;
		int scale_off = b * MLO_LRN_SCALE_BATCH_STRIDE + o * MLO_LRN_SCALE_CHANNEL_STRIDE;
		int bot_x = x + lcl_id0 * MLO_LRN_N_HORIZ_OUT_PIX;
		int bot_y = y + lcl_id1 * MLO_LRN_N_VERT_OUT_PIX;

		_FLOAT prv_exp_scale[MLO_LRN_N_VERT_OUT_PIX][MLO_LRN_N_HORIZ_OUT_PIX];
//		_FLOAT prv_top_df[MLO_LRN_N_VERT_OUT_PIX][MLO_LRN_N_HORIZ_OUT_PIX];

		// load top_diff and scale tiles
		for( int b_j = lcl_id1; b_j < MLO_LRN_LCL_DATA_HEIGHT; b_j += MLO_LRN_GROUP_SZ1)
		{
			int top_y_act = top_y + b_j - MLO_LRN_PAD;

			bool invisibleY = (top_y_act < 0) || (top_y_act >= MLO_LRN_TOP_HEIGHT);

//			top_y_act = (bot_y_act < 0) ? 0 : (bot_y_act >= MLO_LRN_BOT_HEIGHT) ? MLO_LRN_BOT_HEIGHT - 1: bot_y_act;

			int top_df_y_off = top_y_act * MLO_LRN_TOPDF_STRIDE;
			int scale_y_off = top_y_act * MLO_LRN_SCALE_STRIDE;

			int lcl_off_v = b_j * MLO_LRN_LCL_DATA_WIDTH;

			for(int b_i = lcl_id0; b_i < MLO_LRN_LCL_DATA_WIDTH; b_i += MLO_LRN_GROUP_SZ0)
			{

				int top_x_act = top_x + b_i - MLO_LRN_PAD;

				bool invisibleX = (top_x_act < 0) || (top_x_act >= MLO_LRN_TOP_WIDTH);

//				bot_x_act = (bot_x_act < 0) ? 0 : (bot_x_act >= MLO_LRN_BOT_WIDTH) ? MLO_LRN_BOT_WIDTH - 1: bot_x_act;

				_FLOAT top_df_val = top_df[top_df_off + top_df_y_off + top_x_act];
				_FLOAT scale_val = scale[scale_off + scale_y_off + top_x_act];

				top_df_val = (invisibleX || invisibleY)?
							0 :
							top_df_val;
				scale_val = (invisibleX || invisibleY)?
							1.f :
							scale_val;

				top_df_data[lcl_off_v + b_i] = top_df_val;
				ratio_data[lcl_off_v + b_i] = scale_val;

			}
		}

		barrier(CLK_LOCAL_MEM_FENCE);

		// actual top_diffs and scales
		for(int j = 0; j < MLO_LRN_N_VERT_OUT_PIX; ++j)
		{
			int lcl_off_v = (lcl_id1 * MLO_LRN_N_VERT_OUT_PIX + MLO_LRN_PAD + j) *  MLO_LRN_LCL_DATA_WIDTH;
			for(int i = 0; i < MLO_LRN_N_HORIZ_OUT_PIX; i++)
			{
				_FLOAT scale = ratio_data[lcl_off_v + lcl_id0 * MLO_LRN_N_HORIZ_OUT_PIX + MLO_LRN_PAD + i];
				prv_exp_scale[j][i]= native_exp(-beta * native_log(scale));
//				prv_exp_scale[j][i]= pow(scale, -beta);
#if 0
				if (o==0 && b==0 && (bot_x + i) ==2 && (bot_y + j) == 0)
				{
					printf("K:scl: %d %d  %11.9f %11.9f %11.9f\n",
					i, j,
					prv_exp_scale[j][i],
					beta, scale
					);
				}
#endif

//				_FLOAT top_df_val = top_df_data[lcl_off_v + lcl_id0 * MLO_LRN_N_HORIZ_OUT_PIX + MLO_LRN_PAD + i];
//				prv_top_df[j][i] = top_df_val;
			}
		}

// read top and load ratio tile
		int top_off = b * MLO_LRN_TOP_BATCH_STRIDE + o * MLO_LRN_TOP_CHANNEL_STRIDE;
		for( int b_j = lcl_id1; b_j < MLO_LRN_LCL_DATA_HEIGHT; b_j += MLO_LRN_GROUP_SZ1)
		{
			int top_y_act = top_y + b_j - MLO_LRN_PAD;

			bool invisibleY = (top_y_act < 0) || (top_y_act >= MLO_LRN_TOP_HEIGHT);

//			top_y_act = (bot_y_act < 0) ? 0 : (bot_y_act >= MLO_LRN_BOT_HEIGHT) ? MLO_LRN_BOT_HEIGHT - 1: bot_y_act;

			int top_y_off = top_y_act * MLO_LRN_TOP_STRIDE;

			int lcl_off_v = b_j * MLO_LRN_LCL_DATA_WIDTH;

			for(int b_i = lcl_id0; b_i < MLO_LRN_LCL_DATA_WIDTH; b_i += MLO_LRN_GROUP_SZ0)
			{

				int top_x_act = top_x + b_i - MLO_LRN_PAD;

				bool invisibleX = (top_x_act < 0) || (top_x_act >= MLO_LRN_TOP_WIDTH);

//				bot_x_act = (bot_x_act < 0) ? 0 : (bot_x_act >= MLO_LRN_BOT_WIDTH) ? MLO_LRN_BOT_WIDTH - 1: bot_x_act;

				_FLOAT top_val = top[top_off + top_y_off + top_x_act];

				top_val = (invisibleX || invisibleY) ? 0 : top_val;

				_FLOAT top_df_val = top_df_data[lcl_off_v + b_i];

				_FLOAT scale_val = ratio_data[lcl_off_v + b_i];

	// scale val is not 0
				_FLOAT 	ratio_dta =
						(top_df_val * top_val) / scale_val;
#if 0
				if (o==0 && b==0 && (b_i >=0 && b_i < 8) && (b_j == 0))
				{
					printf("K:rdt: %d %d  %11.9f %11.9f %11.9f %11.9f\n",
					b_i, b_j,
					top_df_val, top_val,scale_val,
					ratio_dta
					);
				}
#endif
	// replacing scale with ratio
				ratio_data[lcl_off_v + b_i] = ratio_dta;

			}
		}

		barrier(CLK_LOCAL_MEM_FENCE);

// caculate bot diff
		_FLOAT prv_bot_diff[MLO_LRN_N_VERT_OUT_PIX][MLO_LRN_N_HORIZ_OUT_PIX];

		for(int j = 0; j < MLO_LRN_N_VERT_OUT_PIX; ++j)
		{
			int v_off_v =  (lcl_id1 * MLO_LRN_N_VERT_OUT_PIX + j);
			int hstart = y + v_off_v - MLO_LRN_PAD;
			int hend = min(hstart + MLO_LRN_KERNEL_SZ, MLO_LRN_TOP_HEIGHT + MLO_LRN_PAD);

		// accum offset, vertical
//			int lcl_a_off_v = v_off_v *  MLO_LRN_LCL_DATA_WIDTH;
		// value offset, vertical
			int lcl_v_off_v = (v_off_v + MLO_LRN_PAD) *  MLO_LRN_LCL_DATA_WIDTH;
			for(int i = 0; i < MLO_LRN_N_HORIZ_OUT_PIX; i++)
			{
				_FLOAT prv_ratio_accum = 0;
				int v_off_h = lcl_id0 * MLO_LRN_N_HORIZ_OUT_PIX + i;

				int wstart = x + v_off_h - MLO_LRN_PAD;
				int wend = min(wstart + MLO_LRN_KERNEL_SZ, MLO_LRN_TOP_WIDTH + MLO_LRN_PAD);

				int adj_area_size = (hend - hstart) * (wend - wstart);

		// accum offset, horiz
				int lcl_a_off_h = v_off_h;
		//	value offset, horiz
				int lcl_v_off_h = lcl_a_off_h  + MLO_LRN_PAD;

				for(int k = 0; k < MLO_LRN_KERNEL_SZ; k++)
				{
					for(int l = 0; l < MLO_LRN_KERNEL_SZ; l++)
					{
						prv_ratio_accum += ratio_data[(v_off_v + k) * MLO_LRN_LCL_DATA_WIDTH + lcl_a_off_h + l];
#if 0
				if (o==0 && b==0 && (bot_x + i) ==2 && (bot_y + j) == 0)
				{
					printf("K:prv: %d %d  %d %d  %11.9f %11.9f\n",
					l, k,
					(v_off_v + k) * MLO_LRN_LCL_DATA_WIDTH + lcl_a_off_h + l,
					MLO_LRN_LCL_DATA_WIDTH * MLO_LRN_LCL_DATA_HEIGHT,
					prv_ratio_accum,
					ratio_data[(v_off_v + k)  * MLO_LRN_LCL_DATA_WIDTH + lcl_a_off_h + l]
					);
				}
#endif

					}
				}

				_FLOAT top_df_val = top_df_data[lcl_v_off_v + lcl_v_off_h];
				_FLOAT bot_dta = bot[MLO_LRN_BOT_BATCH_STRIDE * b + MLO_LRN_BOT_CHANNEL_STRIDE *o + MLO_LRN_BOT_STRIDE * (y + v_off_v) + x + v_off_h];
				_FLOAT adj_ratio = 2.f * alpha * beta / adj_area_size;
				_FLOAT prv_accum_ratio =
					adj_ratio * bot_dta * prv_ratio_accum;
				prv_bot_diff[j][i] =
					prv_exp_scale[j][i] * top_df_val - prv_accum_ratio;
#if 0
				if (o==0 && b==0 && (bot_x + i) ==2 && (bot_y + j) == 0)
				{
					printf("K:lrn: %11.9f %11.9f %11.9f\n%11.9f %11.9f %11.9f\n%11.9f\n",
					adj_ratio, bot_dta, prv_ratio_accum,
					prv_exp_scale[j][i], top_df_val, prv_accum_ratio,
					prv_bot_diff[j][i]
					);
				}
#endif
			}
		}

		for( int j = 0; j < MLO_LRN_N_VERT_OUT_PIX; j++)
		{
			for(int i = 0; i < MLO_LRN_N_HORIZ_OUT_PIX; i++)
			{
				if (bot_y + j < MLO_LRN_BOT_HEIGHT && bot_x + i < MLO_LRN_BOT_WIDTH)
				{

					bot_df[MLO_LRN_BOTDF_BATCH_STRIDE * b + MLO_LRN_BOTDF_CHANNEL_STRIDE *o + MLO_LRN_BOTDF_STRIDE * (bot_y + j) + bot_x + i] = prv_bot_diff[j][i];
				}
			}
		}

}

#if (MLO_LRN_N_INPUTS + 2* MLO_LRN_PAD - 1 < MLO_LRN_KERNEL_SZ || MLO_LRN_N_OUTPUTSS + 2* MLO_LRN_PAD - 1 < MLO_LRN_KERNEL_SZ)
#define MLO_LOW_CHNL_COUNT 1
#else
#define MLO_LOW_CHNL_COUNT 0
#endif
__attribute__((reqd_work_group_size(MLO_LRN_GROUP_SZ0,MLO_LRN_GROUP_SZ1,MLO_LRN_GROUP_SZ2)))
__kernel void MLOpenLRNAcrossChannels1(
       const __global _FLOAT * bottom,
       __global _FLOAT * top,
#if MLO_LRN_DO_SCALE
	   __global _FLOAT *scale,
#endif
	   _FLOAT alphaoverarea,
	   _FLOAT alpha,
	   _FLOAT beta,
	   _FLOAT K
	   )
{

		int x = get_global_id(0); // channel x
		int y = get_global_id(1); // channel y
		int b = get_global_id(2); // batch
		_FLOAT accum = 0;
		_FLOAT bot_in[MLO_LRN_KERNEL_SZ];
		_FLOAT bot_in2[MLO_LRN_KERNEL_SZ];
		int c_i = 0, c_o = 0;

		int top_off = 0;
		int scale_off = 0;

		for( c_i = 0; c_i < MLO_LRN_PAD; c_i++)
		{
			_FLOAT bot_val = bottom[MLO_LRN_BOT_BATCH_STRIDE * b + MLO_LRN_BOT_CHANNEL_STRIDE *c_i + MLO_LRN_BOT_STRIDE * y + x];
#if MLO_LOW_CHNL_COUNT
			bot_in[c_i] = (c_i < MLO_LRN_N_INPUTS) ? bot_val : 0;
#endif
			bot_in2[c_i] = bot_in[c_i] * bot_in[c_i];
			accum =
				accum + bot_in2[c_i];
//				fma(bot_in[c_i + MLO_LRN_PAD], bot_in[c_i + MLO_LRN_PAD], accum);

		}

		for( ; c_i < MLO_LRN_KERNEL_SZ; c_i++, c_o++)
		{
			_FLOAT bot_val = bottom[MLO_LRN_BOT_BATCH_STRIDE * b + MLO_LRN_BOT_CHANNEL_STRIDE *c_i + MLO_LRN_BOT_STRIDE * y + x];

#if MLO_LOW_CHNL_COUNT
			bot_in[c_i] = (c_i < MLO_LRN_N_INPUTS) ? bot_val : 0;
#endif
			bot_in2[c_i] = bot_in[c_i] * bot_in[c_i];
			accum =
				accum + bot_in2[c_i];

			top_off = b * MLO_LRN_TOP_BATCH_STRIDE + c_o * MLO_LRN_TOP_CHANNEL_STRIDE + y * MLO_LRN_TOP_STRIDE +x;
			scale_off = b * MLO_LRN_SCALE_BATCH_STRIDE + c_o * MLO_LRN_SCALE_CHANNEL_STRIDE + y * MLO_LRN_SCALE_STRIDE +x;
			_FLOAT prv_scale =
				(K + accum * alphaoverarea);
//				fma(accum,alphaoverarea, 1.f);

			_FLOAT exp_scale =
				native_exp(-beta * native_log(prv_scale));
//				pow(prv_scale,-beta);

			_FLOAT out_val = bot_in[c_o] * exp_scale;
#if MLO_LOW_CHNL_COUNT
			if (c_o < MLO_LRN_N_OUTPUTS)
#endif
			{
#if MLO_LRN_DO_SCALE
				scale[scale_off] = prv_scale;
#endif
				top[top_off] = out_val;
			}
		}

		for( ; c_i < MLO_LRN_N_CHANNELS; c_i++, c_o++)
		{

			_FLOAT prv_bot_in = bottom[MLO_LRN_BOT_BATCH_STRIDE * b + MLO_LRN_BOT_CHANNEL_STRIDE *c_i + MLO_LRN_BOT_STRIDE * y + x];
#if MLO_LOW_CHNL_COUNT
			prv_bot_in = (c_i < MLO_LRN_N_INPUTS) ? prv_bot_in : 0;
#endif
			_FLOAT prv_bot_in2 = prv_bot_in * prv_bot_in;
			accum =
				accum + prv_bot_in2;

			accum =
				accum - bot_in2[0];
//				fma(-bot_in[0], bot_in[0], accum);

			for( int i = 0; i < MLO_LRN_KERNEL_SZ - 1; i++)
			{
				bot_in[i] = bot_in[i+1];
				bot_in2[i] = bot_in2[i+1];
			}

			bot_in[MLO_LRN_KERNEL_SZ - 1] = prv_bot_in;
			bot_in2[MLO_LRN_KERNEL_SZ - 1] = prv_bot_in2;

			top_off = b * MLO_LRN_TOP_BATCH_STRIDE + c_o * MLO_LRN_TOP_CHANNEL_STRIDE + y * MLO_LRN_TOP_STRIDE +x;
			scale_off = b * MLO_LRN_SCALE_BATCH_STRIDE + c_o * MLO_LRN_SCALE_CHANNEL_STRIDE + y * MLO_LRN_SCALE_STRIDE +x;
			_FLOAT prv_scale =
				(K + accum * alphaoverarea);
//				fma(accum,alphaoverarea, 1.f);

			_FLOAT exp_scale =
				native_exp(-beta * native_log(prv_scale));
//				pow(prv_scale,-beta);

			_FLOAT out_val = bot_in[MLO_LRN_PAD] * exp_scale;
#if MLO_LOW_CHNL_COUNT
			if (c_o < MLO_LRN_N_OUTPUTS)
#endif
			{
#if MLO_LRN_DO_SCALE
				scale[scale_off] = prv_scale;
#endif
				top[top_off] = out_val;
			}

		}

		for(  ; c_i < MLO_LRN_N_CHANNELS + MLO_LRN_PAD; c_i++, c_o++)
		{

			accum =
				accum - bot_in2[0];
//				fma(-bot_in[0], bot_in[0], accum);

			for( int i = 0; i < MLO_LRN_KERNEL_SZ - 1; i++)
			{
				bot_in[i] = bot_in[i+1];
				bot_in2[i] = bot_in2[i+1];
			}

			top_off = b * MLO_LRN_TOP_BATCH_STRIDE + c_o * MLO_LRN_TOP_CHANNEL_STRIDE + y * MLO_LRN_TOP_STRIDE + x;
			scale_off = b * MLO_LRN_SCALE_BATCH_STRIDE + c_o * MLO_LRN_SCALE_CHANNEL_STRIDE + y * MLO_LRN_SCALE_STRIDE +x;

			_FLOAT prv_scale =
				(K + accum * alphaoverarea);
//				fma(accum,alphaoverarea, 1.f);

			_FLOAT exp_scale =
				native_exp(-beta * native_log(prv_scale));
	//			pow(prv_scale,-beta);

			_FLOAT out_val = bot_in[MLO_LRN_PAD] * exp_scale;
#if MLO_LOW_CHNL_COUNT
			if (c_o < MLO_LRN_N_OUTPUTS)
#endif
			{
#if MLO_LRN_DO_SCALE
				scale[scale_off] = prv_scale;
#endif
				top[top_off] = out_val;
			}
		}

}

__attribute__((reqd_work_group_size(MLO_LRN_GROUP_SZ0,MLO_LRN_GROUP_SZ1,MLO_LRN_GROUP_SZ2)))
__kernel void MLOpenLRNAcrossChannelsBwd1(
       const __global _FLOAT * top,
	   const __global _FLOAT *	bot,
       const __global _FLOAT * top_df,
	   const __global _FLOAT *	scale,
       __global _FLOAT * bot_df,
	   _FLOAT ratio, //2. * alpha * beta / local_area
	   _FLOAT alpha,
	   _FLOAT beta
	   )
{

		int x = get_global_id(0); // channel x
		int y = get_global_id(1); // channel y
		int b = get_global_id(2); // batch
		_FLOAT accum_ratio = 0;
		_FLOAT top_df_in[MLO_LRN_KERNEL_SZ];
		_FLOAT scale_in[MLO_LRN_KERNEL_SZ];
		_FLOAT ratio_dta[MLO_LRN_KERNEL_SZ];
		int c_i = 0, c_o = 0;
		int bot_df_off = 0;

		for( c_i = 0; c_i < MLO_LRN_PAD; c_i++)
		{

			top_df_in[c_i] = top_df[MLO_LRN_TOPDF_BATCH_STRIDE * b + MLO_LRN_TOPDF_CHANNEL_STRIDE *c_i + MLO_LRN_TOPDF_STRIDE * y + x];
			scale_in[c_i] = scale[MLO_LRN_SCALE_BATCH_STRIDE * b + MLO_LRN_SCALE_CHANNEL_STRIDE * c_i + MLO_LRN_SCALE_STRIDE * y + x];
			_FLOAT top_dta = top[MLO_LRN_TOP_BATCH_STRIDE *b  + MLO_LRN_TOP_CHANNEL_STRIDE * c_i + MLO_LRN_TOP_STRIDE * y + x];

			ratio_dta[c_i] = (top_df_in[c_i] * top_dta) / scale_in[c_i];

#if MLO_LOW_CHNL_COUNT
			ratio_dta[c_i] = (c_i < MLO_LRN_N_OUTPUTS) ? ratio_dta[c_i] : 0;
#endif
#if 0
			if ( x == 5 && y == 11/* && c_o==12 */&& b==10)
			{
				printf("K:a %d %f %f\n",
					c_i,
					accum_ratio,
					ratio_dta[c_i]

				);

			}

#endif

 			accum_ratio =
				accum_ratio + ratio_dta[c_i] ;

		}

		for( ; c_i < MLO_LRN_KERNEL_SZ; c_i++, c_o++)
		{
			top_df_in[c_i] = top_df[MLO_LRN_TOPDF_BATCH_STRIDE * b + MLO_LRN_TOPDF_CHANNEL_STRIDE *c_i + MLO_LRN_TOPDF_STRIDE * y + x];
			scale_in[c_i] = scale[MLO_LRN_SCALE_BATCH_STRIDE * b + MLO_LRN_SCALE_CHANNEL_STRIDE * c_i + MLO_LRN_SCALE_STRIDE * y + x];
			_FLOAT top_dta = top[MLO_LRN_TOP_BATCH_STRIDE *b  + MLO_LRN_TOP_CHANNEL_STRIDE * c_i + MLO_LRN_TOP_STRIDE * y + x];
			ratio_dta[c_i] = (top_df_in[c_i] * top_dta) / scale_in[c_i];
#if MLO_LOW_CHNL_COUNT
			ratio_dta[c_i] = (c_i < MLO_LRN_N_OUTPUTS) ? ratio_dta[c_i] : 0;
#endif

#if 0
			if ( x == 5 && y == 11/* && c_o==12 */&& b==10)
			{
				printf("K:a %d %f %f\n",
					c_i,
					accum_ratio,
					ratio_dta[c_i]

				);

			}

#endif

 			accum_ratio =
				accum_ratio + ratio_dta[c_i] ;
#if MLO_LOW_CHNL_COUNT
			if (c_o < MLO_LRN_N_INPUTS)
#endif
			{
				_FLOAT bot_dta = bot[MLO_LRN_BOT_BATCH_STRIDE * b + MLO_LRN_BOT_CHANNEL_STRIDE *c_o + MLO_LRN_BOT_STRIDE * y + x];

				_FLOAT prv_scale = scale_in[c_o];

				_FLOAT exp_scale =
					native_exp(-beta * native_log(prv_scale));
//					pow(prv_scale, -beta);

				_FLOAT prv_accum_ratio =
					ratio * bot_dta * accum_ratio;

				_FLOAT out_val = top_df_in[c_o] * exp_scale - prv_accum_ratio;

				bot_df_off = MLO_LRN_BOTDF_BATCH_STRIDE * b + MLO_LRN_BOTDF_CHANNEL_STRIDE * c_o + MLO_LRN_BOTDF_STRIDE * y + x;

				bot_df[bot_df_off] = out_val;
			}

		}

		for( ; c_i < MLO_LRN_N_CHANNELS; c_i++, c_o++)
		{

			_FLOAT prv_top_df_in = top_df[MLO_LRN_TOPDF_BATCH_STRIDE * b + MLO_LRN_TOPDF_CHANNEL_STRIDE *c_i + MLO_LRN_TOPDF_STRIDE * y + x];
			_FLOAT prv_scale_in = scale[MLO_LRN_SCALE_BATCH_STRIDE * b + MLO_LRN_SCALE_CHANNEL_STRIDE * c_i + MLO_LRN_SCALE_STRIDE * y + x];
			_FLOAT top_dta = top[MLO_LRN_TOP_BATCH_STRIDE *b  + MLO_LRN_TOP_CHANNEL_STRIDE * c_i + MLO_LRN_TOP_STRIDE * y + x];
			_FLOAT prv_ratio_dta = prv_top_df_in * top_dta / prv_scale_in;
#if MLO_LOW_CHNL_COUNT
			prv_ratio_dta = (c_i < MLO_LRN_N_OUTPUTS) ? prv_ratio_dta : 0;
#endif

#if 0
			if ( x == 5 && y == 11/* && c_o==12 */&& b==10)
			{
				printf("K:a %d %f %f\n",
					c_i,
					accum_ratio,
					prv_ratio_dta

				);

			}

#endif

 			accum_ratio =
				accum_ratio + prv_ratio_dta ;

			accum_ratio =
				accum_ratio - ratio_dta[0];

			for( int i = 0; i < MLO_LRN_KERNEL_SZ - 1; i++)
			{
				top_df_in[i] = top_df_in[i+1];
				scale_in[i] = scale_in[i+1];
				ratio_dta[i] = ratio_dta[i+1];
			}

			top_df_in[MLO_LRN_KERNEL_SZ - 1] = prv_top_df_in;
			scale_in[MLO_LRN_KERNEL_SZ - 1] = prv_scale_in;
			ratio_dta[MLO_LRN_KERNEL_SZ - 1]= prv_ratio_dta;

#if 0
			if ( x == 3 && y == 0/* && c_o==12 */&& b==3)
			{
				printf("K: %d %16.12f %16.12f %16.12f %16.12f %16.12f\n",
					c_i,
					accum_ratio,
					prv_ratio_dta,
					prv_top_df_in,
					top_dta,
					prv_scale_in
				);

			}

#endif

#if MLO_LOW_CHNL_COUNT
			if (c_o < MLO_LRN_N_INPUTS)
#endif
			{
				_FLOAT bot_dta = bot[MLO_LRN_BOT_BATCH_STRIDE * b + MLO_LRN_BOT_CHANNEL_STRIDE *c_o + MLO_LRN_BOT_STRIDE * y + x];

				_FLOAT prv_scale = scale_in[MLO_LRN_PAD];

				_FLOAT exp_scale =
					native_exp(-beta * native_log(prv_scale));
				//				pow(prv_scale,-beta);

				_FLOAT prv_accum_ratio =
					ratio * bot_dta * accum_ratio;

				_FLOAT out_val = top_df_in[MLO_LRN_PAD] * exp_scale - prv_accum_ratio;

				bot_df_off = MLO_LRN_BOTDF_BATCH_STRIDE * b + MLO_LRN_BOTDF_CHANNEL_STRIDE * c_o + MLO_LRN_BOTDF_STRIDE * y + x;

				bot_df[bot_df_off] = out_val;
			}

		}

		for (; c_i < MLO_LRN_N_CHANNELS + MLO_LRN_PAD; c_i++, c_o++)
		{

			accum_ratio =
				accum_ratio - ratio_dta[0];

			for (int i = 0; i < MLO_LRN_KERNEL_SZ - 1; i++)
			{
				top_df_in[i] = top_df_in[i + 1];
				scale_in[i] = scale_in[i + 1];
				ratio_dta[i] = ratio_dta[i + 1];

			}

#if MLO_LOW_CHNL_COUNT
			if (c_o < MLO_LRN_N_INPUTS)
#endif
			{
				_FLOAT bot_dta = bot[MLO_LRN_BOT_BATCH_STRIDE * b + MLO_LRN_BOT_CHANNEL_STRIDE *c_o + MLO_LRN_BOT_STRIDE * y + x];

				_FLOAT prv_scale = scale_in[MLO_LRN_PAD];

				_FLOAT exp_scale =
					native_exp(-beta * native_log(prv_scale));
				//				pow(prv_scale,-beta);

				_FLOAT prv_accum_ratio =
					ratio * bot_dta * accum_ratio;

				_FLOAT out_val = top_df_in[MLO_LRN_PAD] * exp_scale - prv_accum_ratio;

				bot_df_off = MLO_LRN_BOTDF_BATCH_STRIDE * b + MLO_LRN_BOTDF_CHANNEL_STRIDE * c_o + MLO_LRN_BOTDF_STRIDE * y + x;

				bot_df[bot_df_off] = out_val;

#if 0
				if ( x == 5 && y == 11/* && c_o==12 */&& b== 10)
				{
					printf("K: %d %10.8f %10.8f %10.8f %10.8f %10.8f %10.8f %10.8f\n",
						c_i,
						bot_df[bot_df_off],
						top_df_in[MLO_LRN_PAD],
						exp_scale,
						prv_scale,
						-prv_accum_ratio,
						bot_dta,
						accum_ratio
						);

				}

#endif
			}
		}

}


Verify commit right by adding a blank line to test/CodeGenOpenCL/address-spaces-conversions.cl.

git-svn-id: ffe668792ed300d6c2daa1f6eba2e0aa28d7ec6c@266083 91177308-0d34-0410-b5e6-96231b3b80d8

// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -O0 -ffake-address-space-map -cl-std=CL2.0 -emit-llvm -o - | FileCheck %s

// test that we generate address space casts everywhere we need conversions of
// pointers to different address spaces

void test(global int *arg_glob, generic int *arg_gen) {
  int var_priv;
  arg_gen = arg_glob; // implicit cast global -> generic
  // CHECK: %{{[0-9]+}} = addrspacecast i32 addrspace(1)* %{{[0-9]+}} to i32 addrspace(4)*

  arg_gen = &var_priv; // implicit cast with obtaining adr, private -> generic
  // CHECK: %{{[0-9]+}} = addrspacecast i32* %var_priv to i32 addrspace(4)*
  arg_glob = (global int *)arg_gen; // explicit cast
  // CHECK: %{{[0-9]+}} = addrspacecast i32 addrspace(4)* %{{[0-9]+}} to i32 addrspace(1)*
  global int *var_glob =
      (global int *)arg_glob; // explicit cast in the same address space
  // CHECK-NOT: %{{[0-9]+}} = addrspacecast i32 addrspace(1)* %{{[0-9]+}} to i32 addrspace(1)*
  var_priv = arg_gen - arg_glob; // arithmetic operation
  // CHECK: %{{.*}} = ptrtoint i32 addrspace(4)* %{{.*}} to i64
  // CHECK: %{{.*}} = ptrtoint i32 addrspace(1)* %{{.*}} to i64
  var_priv = arg_gen > arg_glob; // comparison
  // CHECK: %{{[0-9]+}} = addrspacecast i32 addrspace(1)* %{{[0-9]+}} to i32 addrspace(4)*
}