another fix

another fix

/*
 * Copyright (c) 2016 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

#ifndef FLT_MAX
#define FLT_MAX         3.402823466e+38F        /* max value */
#endif

#define MLO_N_OUT_HORIZ_READS (MLO_ALIGNED_OUT_SCAN_LN)
#define MLO_OUT_HORIZ_PIX_SZ (MLO_N_OUT_HORIZ_READS * MLO_READ_UNIT)

// number of filter taps in the processing wk_item
#define MLO_WEI_WKITEM 4
// n of of filter blks
#define MLO_WEI_BLK_SZ0 ((MLO_FILTER_SIZE0 + MLO_WEI_WKITEM -1)/MLO_WEI_WKITEM)
#define MLO_WEI_BLK_SZ (MLO_FILTER_SIZE1*MLO_WEI_BLK_SZ0)
// n of filter tiles in the group grid
#define MLO_N_WEI_BLK (MLO_GRP_SZ/ MLO_WEI_BLK_SZ)
// n of steps per scan line to be made in the inner loop
#define MLO_OUT_WEI_SCAN_BLK ((MLO_OUT_WIDTH + MLO_N_WEI_BLK - 1) / MLO_N_WEI_BLK)

// max loop over virtual blocks for small images
#define MLO_MAX_WEI_BLK_LOOP_TMP ((MLO_OUT_WIDTH + MLO_OUT_WEI_SCAN_BLK - 1)/MLO_OUT_WEI_SCAN_BLK)
#if MLO_MAX_WEI_BLK_LOOP_TMP < MLO_N_WEI_BLK
#define MLO_MAX_WEI_BLK_LOOP MLO_MAX_WEI_BLK_LOOP_TMP
#else
#define MLO_MAX_WEI_BLK_LOOP MLO_N_WEI_BLK
#endif

#define MLO_WEI_BLKS_SZ (MLO_MAX_WEI_BLK_LOOP * MLO_WEI_BLK_SZ *MLO_WEI_WKITEM)
#define MLO_WEI_BLKS_LCL_SZ (MLO_WEI_BLKS_SZ * MLO_N_LCL_OUT_MAPS)

#define MLO_OUT_BLK_GRP_PIX_SZ (MLO_OUT_HORIZ_PIX_SZ * MLO_N_ALIGNED_OUT_SCAN_BLK)
#define MLO_OUT_BLK_GRP_WK_SZ (MLO_OUT_BLK_GRP_PIX_SZ / MLO_READ_UNIT)

// extended scan to deal with overshot in the inner loop
#define MLO_OUT_WEI_EXT_SCAN_BLK ((MLO_OUT_HORIZ_PIX_SZ + MLO_N_WEI_BLK - 1) / MLO_N_WEI_BLK)
#define MLO_OUT_HORIZ_PIX_EXT_SZ (MLO_OUT_WEI_EXT_SCAN_BLK * MLO_N_WEI_BLK)
#define MLO_OUT_BLK_GRP_EXT_PIX_SZ (MLO_OUT_HORIZ_PIX_EXT_SZ * MLO_N_ALIGNED_OUT_SCAN_BLK)
#define MLO_OUT_LCL_SZ (MLO_OUT_BLK_GRP_EXT_PIX_SZ)
// LDS OUT SIZE
#define MLO_TOTAL_OUT_LCL_SZ (MLO_N_LCL_OUT_MAPS*MLO_OUT_LCL_SZ)

// input size depends on output scan length and
// number of output scans
// this number is constrained by amount or LDS and size of register file.
// TO DO:: CHECK PADDING!!!
#define MLO_IN_LCL_HEIGHT ((MLO_N_ALIGNED_OUT_SCAN_BLK-1)*MLO_FILTER_STRIDE1 + MLO_FILTER_SIZE1)
#define MLO_N_IN_HORIZ_READS ((((MLO_OUT_HORIZ_PIX_SZ-1)*MLO_FILTER_STRIDE0 + MLO_FILTER_SIZE0) + MLO_READ_UNIT - 1) / MLO_READ_UNIT)
#define MLO_IN_LCL_WIDTH (MLO_N_IN_HORIZ_READS * MLO_READ_UNIT)
#define MLO_IN_BLK_GRP_PIX_SZ (MLO_IN_LCL_WIDTH * MLO_IN_LCL_HEIGHT)
#define MLO_IN_BLK_GRP_WK_SZ (MLO_IN_BLK_GRP_PIX_SZ/MLO_READ_UNIT)
#define MLO_IN_LCL_SZ (MLO_IN_BLK_GRP_PIX_SZ)
// LDS IN SIZE
#define MLO_TOTAL_IN_LCL_SZ (MLO_N_LCL_IN_MAPS*MLO_IN_LCL_SZ)
#define MLO_IN_VERT_READS (MLO_GRP_SZ/MLO_N_IN_HORIZ_READS)

#if (MLO_TOTAL_OUT_LCL_SZ + MLO_TOTAL_IN_LCL_SZ) > (MLO_WEI_BLKS_LCL_SZ)
#define MLO_LCL_SZ (MLO_TOTAL_OUT_LCL_SZ + MLO_TOTAL_IN_LCL_SZ)
#else
#define MLO_LCL_SZ (MLO_WEI_BLKS_LCL_SZ)
#endif

#define MLO_HW_WAVE_ID_SETTING 0

#if MLO_HW_WAVE_ID_SETTING
extern __attribute__((const)) uint __hsail_get_dynwave_id(void);
inline int getWaveId()
{
	int wave_id = 0;

	wave_id = __hsail_get_dynwave_id();
	wave_id = wave_id & MLO_N_PHYS_WAVES_MASK;
	return(wave_id);
}
#else
inline int getWaveId()
{
	int wave_id = 0;

	wave_id = (get_local_id(0) >> MLO_LG2_PHYS_WAVE_SZ);

	return(wave_id);
}
#endif

inline int iDiv(int v, int d)
{
	int r = (int)((float)v / d + 0.00001f);
	return(r);
}

inline int iMod(int v, int u, int d)
{
	int r = v - mul24((int)u,(int)d);
	return(r);
}

inline void ReduceKernel(__local _FLOAT * lcl_blob, _FLOAT *weights_accum, int lcl_id, int scan_lcl, int sum_stride, int unit_len, bool debug)
{
	for (int j = (sum_stride >> 1); j > 0; j >>= 1)
	{
		barrier(CLK_LOCAL_MEM_FENCE);
		if (scan_lcl < j)
		{
			for (int i = 0; i < unit_len; ++i)
			{

				weights_accum[i] += lcl_blob[(lcl_id + j) * unit_len + i];

				lcl_blob[lcl_id * unit_len + i] = weights_accum[i];
			}

		}
	}
}

/*********************************************************************************************************
// wrw algorithm
// data layout.
// registers:
// per wk_item:
// MLO_READ_UNIT x MLO_N_LCL_OUT_MAPS of dy
// group:
// MLO_N_OUT_BLK_GRP blocks of MLO_N_OUT_BLK_GRP_PIX_SZ of dy
//
// LDS:
// data buffer
// MLO_N_LCL_IN_MAPS blocks of MLO_IN_LCL_SZ of x

// dw local buffer keeps 1 set of dweghts calculated at each iteration
	MLO_TEMP_WEI_BUFFER_SZ

//
// inputs:
// read into LDS
// MLO_N_IN_BLK_GRP groups
// output
// fetch
// MLO_N_OUT_BLK_GRP groups

// alg
// for each batch
//		until end of output map (MLO_N_OUT_BLK)
//			load input map block in LDS
//			load output maps in LDS
//          for k in filter size1
//				for l in filter size 0
//					at for each out/in pixel pair op,ip in wk_item
//                  calculate the contribution to a dweights by formula ip.x (input pixel.x) = (op.x * stride.x - pad .x + l) % (filter size 0), ip.y = (op.y * stride.y - pad.y + k) % filter size1,
//					wei[k,l] = in[ip.y, ip.x]*op[op.y, op.x]
//                  lcl_wei[MLO_OUT_BLK_GRP_PIX_SZ * out.grp + [op.y, op.x]] = we[k,l]
//                  accumulate the weights in the wk_item with wei_accum +=  lcl_wei[accum_id], accum_id = MLO_OUT_BLK_GRP*MLO_N_LCL_OUT_MAPS*map_id + k*(filter size 0) + l
//	write out accululate weights

// group layout
// 0 - input channel index
// 1 - output channel index
// 2 - 1

// loop over batches
**********************************************************************************************************/

__attribute__((reqd_work_group_size(MLO_GRP_SZ0, MLO_GRP_SZ1, MLO_GRP_SZ2)))
__kernel void MLOpenCvBwdWrW(
	const __global _FLOAT * top_df,
	const __global _FLOAT * bot,
	__global _FLOAT * weights_df,
#if MLO_CONV_BIAS
	__global _FLOAT * bias_df,
#endif
	_FLOAT padding_val
)
{
// input/output tiles

	__local _FLOAT lcl[(MLO_LCL_SZ)];
	__local _FLOAT * lcl_bot = lcl;
	__local _FLOAT * lcl_top = lcl + MLO_TOTAL_IN_LCL_SZ;

	// guarnteeing an uniformity over a wave
	int wave_id = getWaveId();

	int c_idx_base = get_group_id(1); // input map index base

// register memory
	int o_idx_base = get_group_id(2); // output map index base

	int c_idx = c_idx_base * MLO_N_LCL_IN_MAPS; // input map index

	int o_idx = o_idx_base * (MLO_N_OUT_BLK_GRP * MLO_N_LCL_OUT_MAPS); // output map index

	int lcl_id = get_local_id(0);

// output global read
//	int o_blk_idx = iDiv(lcl_id, MLO_OUT_LCL_SZ);
//	int o_pix_X4 = iMod(lcl_id, o_blk_idx, MLO_OUT_LCL_SZ);
	int o_scan = iDiv(lcl_id, MLO_N_OUT_HORIZ_READS);
	int o_pix4 = iMod(lcl_id, o_scan, MLO_N_OUT_HORIZ_READS);

// input global read
	int i_blk_idx = 0; //iDiv(lcl_id, MLO_IN_LCL_SZ);
	//int c_pix_X4 = iMod(lcl_id, i_blk_idx, MLO_IN_LCL_SZ);
	int c_scan0 = iDiv(lcl_id, MLO_N_IN_HORIZ_READS);
	int c_pix4 = iMod(lcl_id,c_scan0, MLO_N_IN_HORIZ_READS);

	int w_blk_idx = iDiv(lcl_id, MLO_WEI_BLK_SZ);
	int w_idx = iMod(lcl_id, w_blk_idx, MLO_WEI_BLK_SZ);
	int w_y = iDiv(w_idx, MLO_WEI_BLK_SZ0);
	int w_x0 = iMod(w_idx, w_y, MLO_WEI_BLK_SZ0);

// FILTR SPECIFIC !!!!!
	int last_tap_to_remove = (w_x0 + (MLO_WEI_WKITEM - 1)* MLO_WEI_BLK_SZ0 >= MLO_FILTER_SIZE0)? 0 : (-1);

// mask to shut down the overshot filter tap
	__constant int filter_mask0 = ~(1 << MLO_FILTER_SIZE0);
	int working_mask = 0;
// filled with 1 evry stride bit
	for(int i = 0; i < MLO_WEI_WKITEM; ++i)
	{
		working_mask |= (1 << (i*MLO_FILTER_STRIDE0));
	}
// add strting point
	working_mask <<= w_x0;
// clamp to the filter size
	working_mask &= filter_mask0;
// move back to the relative start

	__private _FLOAT pvt_accum[(MLO_N_OUT_BLK_GRP * MLO_N_LCL_OUT_MAPS * MLO_WEI_WKITEM)];

	int gbl_in_off = c_idx * MLO_IN_CHANNEL_STRIDE;
	int gbl_out_off = o_idx * MLO_OUT_CHANNEL_STRIDE;

	for (int i = 0; i < (MLO_N_OUT_BLK_GRP * MLO_N_LCL_OUT_MAPS * MLO_WEI_WKITEM); ++i)
	{
		pvt_accum[i] = 0;
	}

// zero out LDS
	for (int i = 0; i < ( MLO_LCL_SZ ); i += MLO_GRP_SZ)
	{
		lcl[i] = 0;
	}

	barrier(CLK_LOCAL_MEM_FENCE);
// zero out pvt accum
	// over all batches

#if 0
	if (c_idx == 0 && o_idx == 0 && lcl_id == 0)
	{
		printf("K:i: %d %d %d %d %d\n",
			MLO_OUT_WIDTH,
			MLO_OUT_HORIZ_PIX_SZ,
			MLO_OUT_WEI_EXT_SCAN_BLK,
			MLO_N_WEI_BLK,
			MLO_OUT_HORIZ_PIX_EXT_SZ
		);
	}
#endif

#if 1
	for (int b = 0;
		b < MLO_N_BATCH_LOOPS;
		++b,
		gbl_in_off += MLO_N_LCL_BATCHS * MLO_IN_BATCH_STRIDE,
		gbl_out_off += MLO_N_LCL_BATCHS * MLO_OUT_BATCH_STRIDE
		)
	{
		int in_y = 0;
		int out_y = 0;
// prefetch MLO_FILTER_STRIDE1 - MLO_FILTER_PAD1
// LDS UPDATE !!!!
// input scan
		__private _FLOAT in_rd_data[MLO_READ_UNIT];

		int gbl_in_scan_off = 0;
		int gbl_out_scan_off = 0;

		for(int c_scan = c_scan0;  in_y + c_scan < MLO_IN_HEIGHT && c_scan < MLO_FILTER_SIZE1 - MLO_FILTER_PAD1 - 1; c_scan += MLO_IN_VERT_READS)
		{
// TODO :: multiply on right mask if needed
			*(MLO_READ_TYPE*)in_rd_data = *(MLO_READ_TYPE*)&bot[gbl_in_scan_off + c_scan * MLO_IN_STRIDE + c_pix4*MLO_READ_UNIT];
// TO DO:: CHECK HEIGHT
// TO DO:: CHECK PADDING
//			*(MLO_READ_TYPE*)&lcl_bot[(c_scan + MLO_FILTER_PAD1)*MLO_IN_LCL_WIDTH + MLO_FILTER_PAD0 + c_pix4*MLO_READ_UNIT] = *(MLO_READ_TYPE*)in_rd_data;
			for (int i = 0; i < MLO_READ_UNIT; ++i)
			{
				lcl_bot[(c_scan + MLO_FILTER_PAD1)*MLO_IN_LCL_WIDTH + MLO_FILTER_PAD0 + c_pix4*MLO_READ_UNIT + i] = in_rd_data[i];
			}

#if 0
			if (c_idx == 0 && o_idx == 0 && c_scan == 2 /*&& (c_pix4 == 0 || c_pix4 == 1)*/)
			{
				printf("K:i: %d %d %f %f\n",
					lcl_id,
					gbl_in_scan_off + c_scan * MLO_IN_STRIDE + c_pix4*MLO_READ_UNIT,
					in_rd_data[0],
					in_rd_data[2]
				);
			}
#endif

		}

		in_y +=  MLO_FILTER_SIZE1 - MLO_FILTER_PAD1 - 1;

// TO DO: HANDLE PADDING
// over all out blocks
		for (int ob = 0; ob < MLO_N_OUT_BLK; ++ob, in_y += (MLO_IN_LCL_HEIGHT - MLO_FILTER_SIZE1 + 1), out_y += MLO_N_ALIGNED_OUT_SCAN_BLK)
		{

			barrier(CLK_LOCAL_MEM_FENCE);

// fetch input: (MLO_IN_LCL_HEIGHT - MLO_FILTER_SIZE1 + 1)
               // TODO:: HANDLE multiple INPUTS
			   // overshot i shadled by out put
			gbl_in_scan_off = gbl_in_off + mul24(in_y, MLO_IN_STRIDE);

			for (int c_scan = c_scan0;i_blk_idx < MLO_N_LCL_IN_MAPS && in_y + c_scan < MLO_IN_HEIGHT && c_scan <  (MLO_IN_LCL_HEIGHT - MLO_FILTER_SIZE1 + 1); c_scan += MLO_IN_VERT_READS)
			{

					*(MLO_READ_TYPE*)in_rd_data = *(MLO_READ_TYPE*)&bot[gbl_in_scan_off + c_scan * MLO_IN_STRIDE + c_pix4*MLO_READ_UNIT];
//					*(MLO_READ_TYPE*)&lcl_bot[(c_scan + MLO_FILTER_SIZE1 - 1)*MLO_IN_LCL_WIDTH + MLO_FILTER_PAD0 + c_pix4*MLO_READ_UNIT] = *(MLO_READ_TYPE*)in_rd_data;
					for (int i = 0; i < MLO_READ_UNIT; ++i)
					{
						lcl_bot[(c_scan + MLO_FILTER_SIZE1 - 1)*MLO_IN_LCL_WIDTH + MLO_FILTER_PAD0 + c_pix4*MLO_READ_UNIT + i] = in_rd_data[i];
					}

#if 0
					if (c_idx == 0 && o_idx == 0 && in_y + c_scan == 0 && (c_pix4 == 0 || c_pix4 == 1))
					{
						printf("K:i: %d %d %f %f\n",
							lcl_id,
							gbl_in_scan_off + c_scan * MLO_IN_STRIDE + c_pix4*MLO_READ_UNIT,
							in_rd_data[0],
							in_rd_data[2]
						);
					}
#endif

			}

			// ouput scan
			__private _FLOAT out_rd_data[MLO_N_LCL_OUT_MAPS * MLO_READ_UNIT];

			gbl_out_scan_off = gbl_out_off + mul24(out_y, MLO_OUT_STRIDE);

// over all outputs groups

			int gbl_out_scan_off1 = gbl_out_scan_off;
			for(int og = 0; og < MLO_N_OUT_BLK_GRP; ++og, gbl_out_scan_off1 += MLO_N_LCL_OUT_MAPS*MLO_OUT_CHANNEL_STRIDE )
			{
//				barrier(CLK_LOCAL_MEM_FENCE);

// fetch output

				for(int o = 0; o < MLO_N_LCL_OUT_MAPS
						&&  ( o_idx + o < MLO_N_OUTPUTS && out_y + o_scan < MLO_OUT_HEIGHT && o_scan < MLO_N_ALIGNED_OUT_SCAN_BLK)
						; ++o)
				{
						*(MLO_READ_TYPE*)&out_rd_data[o*MLO_READ_UNIT]
							= *(MLO_READ_TYPE*)&top_df[gbl_out_scan_off1 + o*MLO_OUT_CHANNEL_STRIDE + o_scan * MLO_OUT_STRIDE + o_pix4*MLO_READ_UNIT];
#if MLO_OUT_SCAN_NOT_DIVBY4
						if (o_pix4 == (MLO_N_OUT_HORIZ_READS-1))
						{
							for(int i = MLO_READ_UNIT-1; i >= MLO_READ_UNIT - MLO_OUT_N_PIXS_OFF; --i)
							{
	 							out_rd_data[o*MLO_READ_UNIT + i] = 0;
							}
						}
#endif
// write with MLO_OUT_HORIZ_PIX_EXT_SZ stride
//						*(MLO_READ_TYPE*)&lcl_top[o * MLO_OUT_LCL_SZ + o_scan * MLO_OUT_HORIZ_PIX_EXT_SZ + o_pix4*MLO_READ_UNIT] = *(MLO_READ_TYPE*)&out_rd_data[o*MLO_READ_UNIT];
						for (int i = 0; i < MLO_READ_UNIT; ++i)
						{
							lcl_top[o * MLO_OUT_LCL_SZ + o_scan * MLO_OUT_HORIZ_PIX_EXT_SZ + o_pix4*MLO_READ_UNIT + i] = out_rd_data[o*MLO_READ_UNIT + i];
						}

#if 0
						if (c_idx == 0 && o_idx == 0 && og == 0 && o == 0/* && out_y + o_scan == 0*/)
						{
							printf("K:o: %d %d %d %f %f %f\n",
								lcl_id,
								gbl_out_scan_off + o*MLO_OUT_CHANNEL_STRIDE + o_scan * MLO_OUT_STRIDE + o_pix4*MLO_READ_UNIT,
								o * MLO_OUT_LCL_SZ + o_scan * MLO_OUT_HORIZ_PIX_EXT_SZ + o_pix4*MLO_READ_UNIT,
								lcl_top[o * MLO_OUT_LCL_SZ + o_scan * MLO_OUT_HORIZ_PIX_EXT_SZ + o_pix4*MLO_READ_UNIT + 0],
								lcl_top[o * MLO_OUT_LCL_SZ + o_scan * MLO_OUT_HORIZ_PIX_EXT_SZ + o_pix4*MLO_READ_UNIT + 1],
								lcl_top[o * MLO_OUT_LCL_SZ + o_scan * MLO_OUT_HORIZ_PIX_EXT_SZ + o_pix4*MLO_READ_UNIT + 2]
								);
						}
#endif

				}

				barrier(CLK_LOCAL_MEM_FENCE);

// process
// algorithm

#if 1
//				if (w_blk_idx < MLO_MAX_WEI_BLK_LOOP)
				{
					for (int j = 0; j < MLO_N_ALIGNED_OUT_SCAN_BLK; ++j)
					{

						_FLOAT i_vals[MLO_WEI_WKITEM];
						for (int w = 0; w < MLO_WEI_WKITEM - 1; ++w)
						{
							int w_x = w_x0 + w*MLO_WEI_BLK_SZ0;
							int i_off = (j*MLO_FILTER_STRIDE1 + w_y) * MLO_IN_LCL_WIDTH + (w_blk_idx*MLO_OUT_WEI_SCAN_BLK + 0) * MLO_FILTER_STRIDE0 + w_x;
							_FLOAT i_val = lcl_bot[i_off];

							i_vals[w] = i_val;

						}

						// if we overshoot the scanline
						// out data will be 0 by initial setting
						for (int i = 0; i < MLO_OUT_WEI_SCAN_BLK; ++i)
						{

							//						for(int w = 0; w < MLO_WEI_WKITEM; ++w)

							{
								int w_x = w_x0 + (MLO_WEI_WKITEM - 1)* MLO_WEI_BLK_SZ0;
								int i_off = (j*MLO_FILTER_STRIDE1 + w_y) * MLO_IN_LCL_WIDTH + (w_blk_idx*MLO_OUT_WEI_SCAN_BLK + i) * MLO_FILTER_STRIDE0 + w_x;
								_FLOAT i_val = lcl_bot[i_off];

								i_vals[(MLO_WEI_WKITEM - 1)] = i_val;

							}

							for (int o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
							{
								// read with MLO_OUT_HORIX_PIX_EXT_SZ stride
								_FLOAT o_val
									= lcl_top[o*MLO_OUT_LCL_SZ + j * MLO_OUT_HORIZ_PIX_EXT_SZ + (w_blk_idx*MLO_OUT_WEI_SCAN_BLK + i)];

								int w = 0;
								_FLOAT i_val;
								for (/*int w = 0*/; w < MLO_WEI_WKITEM; ++w)
								{

									i_val = i_vals[w];
									pvt_accum[(og * MLO_N_LCL_OUT_MAPS + o) * MLO_WEI_WKITEM + w] += i_val * o_val;

#if 0
									int w_x = w_x0 + w*MLO_WEI_BLK_SZ0;
									if (c_idx == 0 && o_idx == 0 && og == 0 && o == 0 && w_y == 1 && w_x == 1 && w_blk_idx < MLO_MAX_WEI_BLK_LOOP /* && lcl_id < MLO_OUT_WEI_SCAN_BLK * MLO_MAX_WEI_BLK_LOOP * MLO_WEI_BLK_SZ0 * MLO_WEI_WKITEM*/)
									{
										printf("K:s: %d %d %d %d %d %d %f %f %f\n",
											lcl_id,
											j,
											i,
											w,
											last_tap_to_remove,
											o*MLO_OUT_LCL_SZ + j * MLO_OUT_HORIZ_PIX_EXT_SZ + (w_blk_idx*MLO_OUT_WEI_SCAN_BLK + i),
											pvt_accum[(og * MLO_N_LCL_OUT_MAPS + o) * MLO_WEI_WKITEM + w],
											i_val,
											o_val
										);
									}
#endif
								}

								// set input data to zero if MLO_FILTER_SIZE0 is not multiple of MLO_WEI_WKITEM and it's over MLO_FILTER_SIZE0

//								_FLOAT i_val = i_vals[w];
								// not needed becuse it's handled when "virtual" tables are trasnformed into real ones
//								int ii_val = as_uint(i_val) & last_tap_to_remove;
//								i_val = as_float(ii_val);

//								pvt_accum[(og * MLO_N_LCL_OUT_MAPS + o) * MLO_WEI_WKITEM + w] += i_val * o_val;

#if 0
								int w_x = w_x0 + w*MLO_WEI_BLK_SZ0;
								if (c_idx == 0 && o_idx == 0 && og == 0 && o == 0 && w_y == 1 && w_x == 1 && w_blk_idx < MLO_MAX_WEI_BLK_LOOP /* && lcl_id < MLO_OUT_WEI_SCAN_BLK * MLO_MAX_WEI_BLK_LOOP * MLO_WEI_BLK_SZ0 * MLO_WEI_WKITEM*/)
								{
									printf("K:s: %d %d %d %d %d %d %f %f %f\n",
										lcl_id,
										j,
										i,
										w,
										last_tap_to_remove,
										o*MLO_OUT_LCL_SZ + j * MLO_OUT_HORIZ_PIX_EXT_SZ + (w_blk_idx*MLO_OUT_WEI_SCAN_BLK + i),
										pvt_accum[(og * MLO_N_LCL_OUT_MAPS + o) * MLO_WEI_WKITEM + w],
										i_val,
										o_val
									);
								}
#endif

							}

							for (int w = 0; w < MLO_WEI_WKITEM - 1; ++w)
							{
								i_vals[w] = i_vals[w + 1];

							}

						}
					}
				}
#else
						for(int o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
						{
							for(int w = 0; w < MLO_WEI_WKITEM; ++w)
							{
								pvt_accum[(og * MLO_N_LCL_OUT_MAPS + o) * MLO_WEI_WKITEM + w] = lcl_top[(og * MLO_N_LCL_OUT_MAPS + o)] * lcl_bot[w];
							}
						}
#endif

			} // for(; og < (MLO_N_OUT_BLK_GRP; ++og )

			barrier(CLK_LOCAL_MEM_FENCE);

// move data up
			for(int c_scan = c_scan0; c_scan < MLO_FILTER_SIZE1 -1; c_scan += MLO_IN_VERT_READS)
			{
					*(MLO_READ_TYPE*)in_rd_data = *(MLO_READ_TYPE*)&lcl_bot[(c_scan +  (MLO_IN_LCL_HEIGHT - MLO_FILTER_SIZE1 + 1))*(MLO_IN_LCL_WIDTH) + MLO_FILTER_PAD0 + c_pix4*MLO_READ_UNIT];
					*(MLO_READ_TYPE*)&lcl_bot[c_scan*(MLO_IN_LCL_WIDTH) + MLO_FILTER_PAD0 + c_pix4*MLO_READ_UNIT] = *(MLO_READ_TYPE*)in_rd_data;

			}

		} // for (int ob = 0; ob < MLO_N_OUT_BLK; ++ob, in_y += (MLO_IN_LCL_HEIGHT - MLO_FILTER_SIZE1 + 1), out_y += MLO_N_ALIGNED_OUT_SCAN_BLK)
	} // for (int b = 0;

#endif

	int oo = iDiv(lcl_id, (MLO_FILTER_SIZE1*MLO_FILTER_SIZE0));
	int wei_i = iMod(lcl_id, oo, (MLO_FILTER_SIZE1*MLO_FILTER_SIZE0));
	int wei_i_y = iDiv(wei_i, (MLO_FILTER_SIZE0));
	int wei_i_x = iMod(wei_i,wei_i_y, (MLO_FILTER_SIZE0));
	// send it out
	int wei_df_off = mul24(o_idx, (int)MLO_WEI_BATCH_STRIDE)
		// this input channel
		+ mul24(c_idx, (int)MLO_WEI_CHANNEL_STRIDE);

	int wei_lcl_off = 0;
	_FLOAT final_sum = 0;

// save in lcl and orgnize in a proper order
// outputs
//	filter size1
//	  filter size0
// TO DO DEPENDING ON THE GROUP SIZE
	for(int og = 0; og < MLO_N_OUT_BLK_GRP; ++og)
	{
		for(int o = 0;  w_blk_idx < MLO_MAX_WEI_BLK_LOOP/* && lcl_id < MLO_OUT_WEI_SCAN_BLK * MLO_MAX_WEI_BLK_LOOP * MLO_WEI_BLK_SZ0 * MLO_WEI_WKITEM*/ && o < MLO_N_LCL_OUT_MAPS; ++o)
		{
			int w = 0;
			for(; w < MLO_WEI_WKITEM; ++w)
			{
// save "virtual" filter table
				int w_x = w_x0 + w*MLO_WEI_BLK_SZ0;
				wei_lcl_off = ((o * MLO_MAX_WEI_BLK_LOOP + w_blk_idx) * MLO_FILTER_SIZE1  + w_y) * (MLO_WEI_BLK_SZ0 *MLO_WEI_WKITEM) + w_x;
				lcl_bot[wei_lcl_off] = pvt_accum[(og * MLO_N_LCL_OUT_MAPS + o) * MLO_WEI_WKITEM + w];
#if 0
				// wei_lcl_off == 1020 || wei_lcl_off == 1080 || wei_lcl_off == 1140)
				if (c_idx == 0 && o_idx == 0 && og == 0 && o == 0 && w_y == 1 && w_x == 1/* && lcl_id < MLO_OUT_WEI_SCAN_BLK * MLO_MAX_WEI_BLK_LOOP * MLO_WEI_BLK_SZ0 * MLO_WEI_WKITEM*/)
				{
					printf("K:u: %d %d %d %f %f\n",
						lcl_id,
						w_blk_idx,
						wei_lcl_off,
						lcl_bot[wei_lcl_off],
						pvt_accum[(og * MLO_N_LCL_OUT_MAPS + o) * MLO_WEI_WKITEM + w]
					);
				}
#endif

			}

		}

		barrier(CLK_LOCAL_MEM_FENCE);
#if 1
// read into real filter table

		if (lcl_id < ( MLO_N_LCL_OUT_MAPS *MLO_FILTER_SIZE1*MLO_FILTER_SIZE0))
		{
			final_sum = 0;
			for(int i = 0; i < MLO_MAX_WEI_BLK_LOOP; ++i)
			{
				final_sum += lcl_bot[((oo * MLO_MAX_WEI_BLK_LOOP + i) * MLO_FILTER_SIZE1 + wei_i_y) * (MLO_WEI_BLK_SZ0 *MLO_WEI_WKITEM) + wei_i_x];
#if 0
				if (c_idx == 0 && o_idx == 0  && og == 0 && oo  == 0 && wei_i_y == 1 && wei_i_x == 1)
				{
					printf("K:fs: %d %d %d  %f %f\n",
						lcl_id,
						i,
						((oo * MLO_MAX_WEI_BLK_LOOP + i) * MLO_FILTER_SIZE1 + wei_i_y) * (MLO_WEI_BLK_SZ0 *MLO_WEI_WKITEM) + wei_i_x,
						final_sum,
						lcl_bot[((oo * MLO_MAX_WEI_BLK_LOOP + i) * MLO_FILTER_SIZE1 + wei_i_y) * (MLO_WEI_BLK_SZ0 *MLO_WEI_WKITEM) + wei_i_x]
					);
				}
#endif
			}

#if 1

			weights_df[wei_df_off + (og *  MLO_N_LCL_OUT_MAPS + oo) * MLO_WEI_BATCH_STRIDE + wei_i] = final_sum; //lcl_bot[lcl_id]; //

#if 0
			if (og == 1 && oo == 0 && wei_i == 0)
			{

				printf("K:o: %d %d %f\n",
					wei_df_off,
					wei_df_off + (og *  MLO_N_LCL_OUT_MAPS + oo) * MLO_WEI_BATCH_STRIDE + wei_i,
					weights_df[wei_df_off + (og *  MLO_N_LCL_OUT_MAPS + oo) * MLO_WEI_BATCH_STRIDE + wei_i]
					);
			}
#endif
#else
			_FLOAT t_accum = 0;

			for (int og = 0; og < MLO_N_OUT_BLK_GRP; ++og)
			{
				for (int o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
				{
					for (int w = 0; w < MLO_WEI_WKITEM; ++w)
					{
						t_accum += pvt_accum[(og * MLO_N_LCL_OUT_MAPS + o) * MLO_WEI_WKITEM + w];
					}
				}
			}

			weights_df[lcl_id] = t_accum;
#endif

		}
#endif
		barrier(CLK_LOCAL_MEM_FENCE);

	} // for(int og = 0; og < MLO_N_OUT_BLK_GRP; ++og)

}

/*
 * Copyright (c) 2016 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

#ifndef FLT_MAX
#define FLT_MAX         3.402823466e+38F        /* max value */
#endif

#define MLO_N_OUT_HORIZ_READS (MLO_ALIGNED_OUT_SCAN_LN)
#define MLO_OUT_HORIZ_PIX_SZ (MLO_N_OUT_HORIZ_READS * MLO_READ_UNIT)

// number of filter taps in the processing wk_item
#define MLO_WEI_WKITEM 4
// n of of filter blks
#define MLO_WEI_BLK_SZ0 ((MLO_FILTER_SIZE0 + MLO_WEI_WKITEM -1)/MLO_WEI_WKITEM)
#define MLO_WEI_BLK_SZ (MLO_FILTER_SIZE1*MLO_WEI_BLK_SZ0)
// n of filter tiles in the group grid
#define MLO_N_WEI_BLK (MLO_GRP_SZ/ MLO_WEI_BLK_SZ)
// n of steps per scan line to be made in the inner loop
#define MLO_OUT_WEI_SCAN_BLK ((MLO_OUT_WIDTH + MLO_N_WEI_BLK - 1) / MLO_N_WEI_BLK)

// max loop over virtual blocks for small images
#define MLO_MAX_WEI_BLK_LOOP_TMP ((MLO_OUT_WIDTH + MLO_OUT_WEI_SCAN_BLK - 1)/MLO_OUT_WEI_SCAN_BLK)
#if MLO_MAX_WEI_BLK_LOOP_TMP < MLO_N_WEI_BLK
#define MLO_MAX_WEI_BLK_LOOP MLO_MAX_WEI_BLK_LOOP_TMP
#else
#define MLO_MAX_WEI_BLK_LOOP MLO_N_WEI_BLK
#endif

#define MLO_WEI_BLKS_SZ (MLO_MAX_WEI_BLK_LOOP * MLO_WEI_BLK_SZ *MLO_WEI_WKITEM)
#define MLO_WEI_BLKS_LCL_SZ (MLO_WEI_BLKS_SZ * MLO_N_LCL_OUT_MAPS)

#define MLO_OUT_BLK_GRP_PIX_SZ (MLO_OUT_HORIZ_PIX_SZ * MLO_N_ALIGNED_OUT_SCAN_BLK)
#define MLO_OUT_BLK_GRP_WK_SZ (MLO_OUT_BLK_GRP_PIX_SZ / MLO_READ_UNIT)

// extended scan to deal with overshot in the inner loop
#define MLO_OUT_WEI_EXT_SCAN_BLK ((MLO_OUT_HORIZ_PIX_SZ + MLO_N_WEI_BLK - 1) / MLO_N_WEI_BLK)
#define MLO_OUT_HORIZ_PIX_EXT_SZ ((((MLO_OUT_WEI_EXT_SCAN_BLK * MLO_N_WEI_BLK) + MLO_READ_UNIT - 1) / MLO_READ_UNIT) * MLO_READ_UNIT)
#define MLO_OUT_BLK_GRP_EXT_PIX_SZ (MLO_OUT_HORIZ_PIX_EXT_SZ * MLO_N_ALIGNED_OUT_SCAN_BLK)
#define MLO_OUT_LCL_SZ (MLO_OUT_BLK_GRP_EXT_PIX_SZ)
// LDS OUT SIZE
#define MLO_TOTAL_OUT_LCL_SZ (MLO_N_LCL_OUT_MAPS*MLO_OUT_LCL_SZ)

// input size depends on output scan length and
// number of output scans
// this number is constrained by amount or LDS and size of register file.
// TO DO:: CHECK PADDING!!!
#define MLO_IN_LCL_HEIGHT ((MLO_N_ALIGNED_OUT_SCAN_BLK-1)*MLO_FILTER_STRIDE1 + MLO_FILTER_SIZE1)
#define MLO_N_IN_HORIZ_READS ((((MLO_OUT_HORIZ_PIX_SZ-1)*MLO_FILTER_STRIDE0 + MLO_FILTER_SIZE0) + MLO_READ_UNIT - 1) / MLO_READ_UNIT)
#define MLO_IN_LCL_WIDTH (MLO_N_IN_HORIZ_READS * MLO_READ_UNIT)
#define MLO_IN_BLK_GRP_PIX_SZ (MLO_IN_LCL_WIDTH * MLO_IN_LCL_HEIGHT)
#define MLO_IN_BLK_GRP_WK_SZ (MLO_IN_BLK_GRP_PIX_SZ/MLO_READ_UNIT)
#define MLO_IN_LCL_SZ (MLO_IN_BLK_GRP_PIX_SZ)
// LDS IN SIZE
#define MLO_TOTAL_IN_LCL_SZ (MLO_N_LCL_IN_MAPS*MLO_IN_LCL_SZ)
#define MLO_IN_VERT_READS (MLO_GRP_SZ/MLO_N_IN_HORIZ_READS)

#if (MLO_TOTAL_OUT_LCL_SZ + MLO_TOTAL_IN_LCL_SZ) > (MLO_WEI_BLKS_LCL_SZ)
#define MLO_LCL_SZ (MLO_TOTAL_OUT_LCL_SZ + MLO_TOTAL_IN_LCL_SZ)
#else
#define MLO_LCL_SZ (MLO_WEI_BLKS_LCL_SZ)
#endif

#define MLO_HW_WAVE_ID_SETTING 0

#if MLO_HW_WAVE_ID_SETTING
extern __attribute__((const)) uint __hsail_get_dynwave_id(void);
inline int getWaveId()
{
	int wave_id = 0;

	wave_id = __hsail_get_dynwave_id();
	wave_id = wave_id & MLO_N_PHYS_WAVES_MASK;
	return(wave_id);
}
#else
inline int getWaveId()
{
	int wave_id = 0;

	wave_id = (get_local_id(0) >> MLO_LG2_PHYS_WAVE_SZ);

	return(wave_id);
}
#endif

inline int iDiv(int v, int d)
{
	int r = (int)((float)v / d + 0.00001f);
	return(r);
}

inline int iMod(int v, int u, int d)
{
	int r = v - mul24((int)u,(int)d);
	return(r);
}

inline void ReduceKernel(__local _FLOAT * lcl_blob, _FLOAT *weights_accum, int lcl_id, int scan_lcl, int sum_stride, int unit_len, bool debug)
{
	for (int j = (sum_stride >> 1); j > 0; j >>= 1)
	{
		barrier(CLK_LOCAL_MEM_FENCE);
		if (scan_lcl < j)
		{
			for (int i = 0; i < unit_len; ++i)
			{

				weights_accum[i] += lcl_blob[(lcl_id + j) * unit_len + i];

				lcl_blob[lcl_id * unit_len + i] = weights_accum[i];
			}

		}
	}
}

/*********************************************************************************************************
// wrw algorithm
// data layout.
// registers:
// per wk_item:
// MLO_READ_UNIT x MLO_N_LCL_OUT_MAPS of dy
// group:
// MLO_N_OUT_BLK_GRP blocks of MLO_N_OUT_BLK_GRP_PIX_SZ of dy
//
// LDS:
// data buffer
// MLO_N_LCL_IN_MAPS blocks of MLO_IN_LCL_SZ of x

// dw local buffer keeps 1 set of dweghts calculated at each iteration
	MLO_TEMP_WEI_BUFFER_SZ

//
// inputs:
// read into LDS
// MLO_N_IN_BLK_GRP groups
// output
// fetch
// MLO_N_OUT_BLK_GRP groups

// alg
// for each batch
//		until end of output map (MLO_N_OUT_BLK)
//			load input map block in LDS
//			load output maps in LDS
//          for k in filter size1
//				for l in filter size 0
//					at for each out/in pixel pair op,ip in wk_item
//                  calculate the contribution to a dweights by formula ip.x (input pixel.x) = (op.x * stride.x - pad .x + l) % (filter size 0), ip.y = (op.y * stride.y - pad.y + k) % filter size1,
//					wei[k,l] = in[ip.y, ip.x]*op[op.y, op.x]
//                  lcl_wei[MLO_OUT_BLK_GRP_PIX_SZ * out.grp + [op.y, op.x]] = we[k,l]
//                  accumulate the weights in the wk_item with wei_accum +=  lcl_wei[accum_id], accum_id = MLO_OUT_BLK_GRP*MLO_N_LCL_OUT_MAPS*map_id + k*(filter size 0) + l
//	write out accululate weights

// group layout
// 0 - input channel index
// 1 - output channel index
// 2 - 1

// loop over batches
**********************************************************************************************************/

__attribute__((reqd_work_group_size(MLO_GRP_SZ0, MLO_GRP_SZ1, MLO_GRP_SZ2)))
__kernel void MLOpenCvBwdWrW(
	const __global _FLOAT * top_df,
	const __global _FLOAT * bot,
	__global _FLOAT * weights_df,
#if MLO_CONV_BIAS
	__global _FLOAT * bias_df,
#endif
	_FLOAT padding_val
)
{
// input/output tiles

	__local _FLOAT lcl[(MLO_LCL_SZ)];
	__local _FLOAT * lcl_bot = lcl;
	__local _FLOAT * lcl_top = lcl + MLO_TOTAL_IN_LCL_SZ;

	// guarnteeing an uniformity over a wave
	int wave_id = getWaveId();

	int c_idx_base = get_group_id(1); // input map index base

// register memory
	int o_idx_base = get_group_id(2); // output map index base

	int c_idx = c_idx_base * MLO_N_LCL_IN_MAPS; // input map index

	int o_idx = o_idx_base * (MLO_N_OUT_BLK_GRP * MLO_N_LCL_OUT_MAPS); // output map index

	int lcl_id = get_local_id(0);

// output global read
//	int o_blk_idx = iDiv(lcl_id, MLO_OUT_LCL_SZ);
//	int o_pix_X4 = iMod(lcl_id, o_blk_idx, MLO_OUT_LCL_SZ);
	int o_scan = iDiv(lcl_id, MLO_N_OUT_HORIZ_READS);
	int o_pix4 = iMod(lcl_id, o_scan, MLO_N_OUT_HORIZ_READS);

// input global read
	int i_blk_idx = 0; //iDiv(lcl_id, MLO_IN_LCL_SZ);
	//int c_pix_X4 = iMod(lcl_id, i_blk_idx, MLO_IN_LCL_SZ);
	int c_scan0 = iDiv(lcl_id, MLO_N_IN_HORIZ_READS);
	int c_pix4 = iMod(lcl_id,c_scan0, MLO_N_IN_HORIZ_READS);

	int w_blk_idx = iDiv(lcl_id, MLO_WEI_BLK_SZ);
	int w_idx = iMod(lcl_id, w_blk_idx, MLO_WEI_BLK_SZ);
	int w_y = iDiv(w_idx, MLO_WEI_BLK_SZ0);
	int w_x0 = iMod(w_idx, w_y, MLO_WEI_BLK_SZ0);

// FILTR SPECIFIC !!!!!
	int last_tap_to_remove = (w_x0 + (MLO_WEI_WKITEM - 1)* MLO_WEI_BLK_SZ0 >= MLO_FILTER_SIZE0)? 0 : (-1);

// mask to shut down the overshot filter tap
	__constant int filter_mask0 = ~(1 << MLO_FILTER_SIZE0);
	int working_mask = 0;
// filled with 1 evry stride bit
	for(int i = 0; i < MLO_WEI_WKITEM; ++i)
	{
		working_mask |= (1 << (i*MLO_FILTER_STRIDE0));
	}
// add strting point
	working_mask <<= w_x0;
// clamp to the filter size
	working_mask &= filter_mask0;
// move back to the relative start

	__private _FLOAT pvt_accum[(MLO_N_OUT_BLK_GRP * MLO_N_LCL_OUT_MAPS * MLO_WEI_WKITEM)];

	int gbl_in_off = c_idx * MLO_IN_CHANNEL_STRIDE;
	int gbl_out_off = o_idx * MLO_OUT_CHANNEL_STRIDE;

	for (int i = 0; i < (MLO_N_OUT_BLK_GRP * MLO_N_LCL_OUT_MAPS * MLO_WEI_WKITEM); ++i)
	{
		pvt_accum[i] = 0;
	}

// zero out LDS
	for (int i = 0; i < ( MLO_LCL_SZ ); i += MLO_GRP_SZ)
	{
		lcl[i] = 0;
	}

	barrier(CLK_LOCAL_MEM_FENCE);
// zero out pvt accum
	// over all batches

#if 0
	if (c_idx == 0 && o_idx == 0 && lcl_id == 0)
	{
		printf("K:i: %d %d %d %d %d\n",
			MLO_OUT_WIDTH,
			MLO_OUT_HORIZ_PIX_SZ,
			MLO_OUT_WEI_EXT_SCAN_BLK,
			MLO_N_WEI_BLK,
			MLO_OUT_HORIZ_PIX_EXT_SZ
		);
	}
#endif

#if 1
	for (int b = 0;
		b < MLO_N_BATCH_LOOPS;
		++b,
		gbl_in_off += MLO_N_LCL_BATCHS * MLO_IN_BATCH_STRIDE,
		gbl_out_off += MLO_N_LCL_BATCHS * MLO_OUT_BATCH_STRIDE
		)
	{
		int in_y = 0;
		int out_y = 0;
// prefetch MLO_FILTER_STRIDE1 - MLO_FILTER_PAD1
// LDS UPDATE !!!!
// input scan
		__private _FLOAT in_rd_data[MLO_READ_UNIT];

		int gbl_in_scan_off = 0;
		int gbl_out_scan_off = 0;

		for(int c_scan = c_scan0;  in_y + c_scan < MLO_IN_HEIGHT && c_scan < MLO_FILTER_SIZE1 - MLO_FILTER_PAD1 - 1; c_scan += MLO_IN_VERT_READS)
		{
// TODO :: multiply on right mask if needed
			*(MLO_READ_TYPE*)in_rd_data = *(MLO_READ_TYPE*)&bot[gbl_in_scan_off + c_scan * MLO_IN_STRIDE + c_pix4*MLO_READ_UNIT];
// TO DO:: CHECK HEIGHT
// TO DO:: CHECK PADDING
//			*(MLO_READ_TYPE*)&lcl_bot[(c_scan + MLO_FILTER_PAD1)*MLO_IN_LCL_WIDTH + MLO_FILTER_PAD0 + c_pix4*MLO_READ_UNIT] = *(MLO_READ_TYPE*)in_rd_data;
			for (int i = 0; i < MLO_READ_UNIT; ++i)
			{
				lcl_bot[(c_scan + MLO_FILTER_PAD1)*MLO_IN_LCL_WIDTH + MLO_FILTER_PAD0 + c_pix4*MLO_READ_UNIT + i] = in_rd_data[i];
			}

#if 0
			if (c_idx == 0 && o_idx == 0 && c_scan == 2 /*&& (c_pix4 == 0 || c_pix4 == 1)*/)
			{
				printf("K:i: %d %d %f %f\n",
					lcl_id,
					gbl_in_scan_off + c_scan * MLO_IN_STRIDE + c_pix4*MLO_READ_UNIT,
					in_rd_data[0],
					in_rd_data[2]
				);
			}
#endif

		}

		in_y +=  MLO_FILTER_SIZE1 - MLO_FILTER_PAD1 - 1;

// TO DO: HANDLE PADDING
// over all out blocks
		for (int ob = 0; ob < MLO_N_OUT_BLK; ++ob, in_y += (MLO_IN_LCL_HEIGHT - MLO_FILTER_SIZE1 + 1), out_y += MLO_N_ALIGNED_OUT_SCAN_BLK)
		{

			barrier(CLK_LOCAL_MEM_FENCE);

// fetch input: (MLO_IN_LCL_HEIGHT - MLO_FILTER_SIZE1 + 1)
               // TODO:: HANDLE multiple INPUTS
			   // overshot i shadled by out put
			gbl_in_scan_off = gbl_in_off + mul24(in_y, MLO_IN_STRIDE);

			for (int c_scan = c_scan0;i_blk_idx < MLO_N_LCL_IN_MAPS && in_y + c_scan < MLO_IN_HEIGHT && c_scan <  (MLO_IN_LCL_HEIGHT - MLO_FILTER_SIZE1 + 1); c_scan += MLO_IN_VERT_READS)
			{

					*(MLO_READ_TYPE*)in_rd_data = *(MLO_READ_TYPE*)&bot[gbl_in_scan_off + c_scan * MLO_IN_STRIDE + c_pix4*MLO_READ_UNIT];
//					*(MLO_READ_TYPE*)&lcl_bot[(c_scan + MLO_FILTER_SIZE1 - 1)*MLO_IN_LCL_WIDTH + MLO_FILTER_PAD0 + c_pix4*MLO_READ_UNIT] = *(MLO_READ_TYPE*)in_rd_data;
					for (int i = 0; i < MLO_READ_UNIT; ++i)
					{
						lcl_bot[(c_scan + MLO_FILTER_SIZE1 - 1)*MLO_IN_LCL_WIDTH + MLO_FILTER_PAD0 + c_pix4*MLO_READ_UNIT + i] = in_rd_data[i];
					}

#if 0
					if (c_idx == 0 && o_idx == 0 && in_y + c_scan == 0 && (c_pix4 == 0 || c_pix4 == 1))
					{
						printf("K:i: %d %d %f %f\n",
							lcl_id,
							gbl_in_scan_off + c_scan * MLO_IN_STRIDE + c_pix4*MLO_READ_UNIT,
							in_rd_data[0],
							in_rd_data[2]
						);
					}
#endif

			}

			// ouput scan
			__private _FLOAT out_rd_data[MLO_N_LCL_OUT_MAPS * MLO_READ_UNIT];

			gbl_out_scan_off = gbl_out_off + mul24(out_y, MLO_OUT_STRIDE);

// over all outputs groups

			int gbl_out_scan_off1 = gbl_out_scan_off;
			for(int og = 0; og < MLO_N_OUT_BLK_GRP; ++og, gbl_out_scan_off1 += MLO_N_LCL_OUT_MAPS*MLO_OUT_CHANNEL_STRIDE )
			{
				barrier(CLK_LOCAL_MEM_FENCE);

// fetch output

				for(int o = 0; o < MLO_N_LCL_OUT_MAPS
						&&  ( o_idx + o < MLO_N_OUTPUTS && out_y + o_scan < MLO_OUT_HEIGHT && o_scan < MLO_N_ALIGNED_OUT_SCAN_BLK)
						; ++o)
				{
						*(MLO_READ_TYPE*)&out_rd_data[o*MLO_READ_UNIT]
							= *(MLO_READ_TYPE*)&top_df[gbl_out_scan_off1 + o*MLO_OUT_CHANNEL_STRIDE + o_scan * MLO_OUT_STRIDE + o_pix4*MLO_READ_UNIT];
#if MLO_OUT_SCAN_NOT_DIVBY4
						if (o_pix4 == (MLO_N_OUT_HORIZ_READS-1))
						{
							for(int i = MLO_READ_UNIT-1; i >= MLO_READ_UNIT - MLO_OUT_N_PIXS_OFF; --i)
							{
	 							out_rd_data[o*MLO_READ_UNIT + i] = 0;
							}
						}
#endif
// write with MLO_OUT_HORIZ_PIX_EXT_SZ stride
//						*(MLO_READ_TYPE*)&lcl_top[o * MLO_OUT_LCL_SZ + o_scan * MLO_OUT_HORIZ_PIX_EXT_SZ + o_pix4*MLO_READ_UNIT] = *(MLO_READ_TYPE*)&out_rd_data[o*MLO_READ_UNIT];
						for (int i = 0; i < MLO_READ_UNIT; ++i)
						{
							lcl_top[o * MLO_OUT_LCL_SZ + o_scan * MLO_OUT_HORIZ_PIX_EXT_SZ + o_pix4*MLO_READ_UNIT + i] = out_rd_data[o*MLO_READ_UNIT + i];
						}

#if 0
						if (c_idx == 0 && o_idx == 0 && og == 0 && o == 0/* && out_y + o_scan == 0*/)
						{
							printf("K:o: %d %d %d %f %f %f\n",
								lcl_id,
								gbl_out_scan_off + o*MLO_OUT_CHANNEL_STRIDE + o_scan * MLO_OUT_STRIDE + o_pix4*MLO_READ_UNIT,
								o * MLO_OUT_LCL_SZ + o_scan * MLO_OUT_HORIZ_PIX_EXT_SZ + o_pix4*MLO_READ_UNIT,
								lcl_top[o * MLO_OUT_LCL_SZ + o_scan * MLO_OUT_HORIZ_PIX_EXT_SZ + o_pix4*MLO_READ_UNIT + 0],
								lcl_top[o * MLO_OUT_LCL_SZ + o_scan * MLO_OUT_HORIZ_PIX_EXT_SZ + o_pix4*MLO_READ_UNIT + 1],
								lcl_top[o * MLO_OUT_LCL_SZ + o_scan * MLO_OUT_HORIZ_PIX_EXT_SZ + o_pix4*MLO_READ_UNIT + 2]
								);
						}
#endif

				}

				barrier(CLK_LOCAL_MEM_FENCE);

// process
// algorithm

#if 1
//				if (w_blk_idx < MLO_MAX_WEI_BLK_LOOP)
				{
					for (int j = 0; j < MLO_N_ALIGNED_OUT_SCAN_BLK; ++j)
					{

						_FLOAT i_vals[MLO_WEI_WKITEM];
						for (int w = 0; w < MLO_WEI_WKITEM - 1; ++w)
						{
							int w_x = w_x0 + w*MLO_WEI_BLK_SZ0;
							int i_off = (j*MLO_FILTER_STRIDE1 + w_y) * MLO_IN_LCL_WIDTH + (w_blk_idx*MLO_OUT_WEI_SCAN_BLK + 0) * MLO_FILTER_STRIDE0 + w_x;
							_FLOAT i_val = lcl_bot[i_off];

							i_vals[w] = i_val;

						}

						// if we overshoot the scanline
						// out data will be 0 by initial setting
						for (int i = 0; i < MLO_OUT_WEI_SCAN_BLK; ++i)
						{

							//						for(int w = 0; w < MLO_WEI_WKITEM; ++w)

							{
								int w_x = w_x0 + (MLO_WEI_WKITEM - 1)* MLO_WEI_BLK_SZ0;
								int i_off = (j*MLO_FILTER_STRIDE1 + w_y) * MLO_IN_LCL_WIDTH + (w_blk_idx*MLO_OUT_WEI_SCAN_BLK + i) * MLO_FILTER_STRIDE0 + w_x;
								_FLOAT i_val = lcl_bot[i_off];

								i_vals[(MLO_WEI_WKITEM - 1)] = i_val;

							}

							for (int o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
							{
								// read with MLO_OUT_HORIX_PIX_EXT_SZ stride
								_FLOAT o_val
									= lcl_top[o*MLO_OUT_LCL_SZ + j * MLO_OUT_HORIZ_PIX_EXT_SZ + (w_blk_idx*MLO_OUT_WEI_SCAN_BLK + i)];

								int w = 0;
								_FLOAT i_val;
								for (/*int w = 0*/; w < MLO_WEI_WKITEM; ++w)
								{

									i_val = i_vals[w];
									pvt_accum[(og * MLO_N_LCL_OUT_MAPS + o) * MLO_WEI_WKITEM + w] += i_val * o_val;

#if 0
									int w_x = w_x0 + w*MLO_WEI_BLK_SZ0;
									if (c_idx == 0 && o_idx == 0 && og == 0 && o == 0 && w_y == 1 && w_x == 1 && w_blk_idx < MLO_MAX_WEI_BLK_LOOP /* && lcl_id < MLO_OUT_WEI_SCAN_BLK * MLO_MAX_WEI_BLK_LOOP * MLO_WEI_BLK_SZ0 * MLO_WEI_WKITEM*/)
									{
										printf("K:s: %d %d %d %d %d %d %f %f %f\n",
											lcl_id,
											j,
											i,
											w,
											last_tap_to_remove,
											o*MLO_OUT_LCL_SZ + j * MLO_OUT_HORIZ_PIX_EXT_SZ + (w_blk_idx*MLO_OUT_WEI_SCAN_BLK + i),
											pvt_accum[(og * MLO_N_LCL_OUT_MAPS + o) * MLO_WEI_WKITEM + w],
											i_val,
											o_val
										);
									}
#endif
								}

								// set input data to zero if MLO_FILTER_SIZE0 is not multiple of MLO_WEI_WKITEM and it's over MLO_FILTER_SIZE0

//								_FLOAT i_val = i_vals[w];
								// not needed becuse it's handled when "virtual" tables are trasnformed into real ones
//								int ii_val = as_uint(i_val) & last_tap_to_remove;
//								i_val = as_float(ii_val);

//								pvt_accum[(og * MLO_N_LCL_OUT_MAPS + o) * MLO_WEI_WKITEM + w] += i_val * o_val;

#if 0
								int w_x = w_x0 + w*MLO_WEI_BLK_SZ0;
								if (c_idx == 0 && o_idx == 0 && og == 0 && o == 0 && w_y == 1 && w_x == 1 && w_blk_idx < MLO_MAX_WEI_BLK_LOOP /* && lcl_id < MLO_OUT_WEI_SCAN_BLK * MLO_MAX_WEI_BLK_LOOP * MLO_WEI_BLK_SZ0 * MLO_WEI_WKITEM*/)
								{
									printf("K:s: %d %d %d %d %d %d %f %f %f\n",
										lcl_id,
										j,
										i,
										w,
										last_tap_to_remove,
										o*MLO_OUT_LCL_SZ + j * MLO_OUT_HORIZ_PIX_EXT_SZ + (w_blk_idx*MLO_OUT_WEI_SCAN_BLK + i),
										pvt_accum[(og * MLO_N_LCL_OUT_MAPS + o) * MLO_WEI_WKITEM + w],
										i_val,
										o_val
									);
								}
#endif

							}

							for (int w = 0; w < MLO_WEI_WKITEM - 1; ++w)
							{
								i_vals[w] = i_vals[w + 1];

							}

						}
					}
				}
#else
						for(int o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
						{
							for(int w = 0; w < MLO_WEI_WKITEM; ++w)
							{
								pvt_accum[(og * MLO_N_LCL_OUT_MAPS + o) * MLO_WEI_WKITEM + w] = lcl_top[(og * MLO_N_LCL_OUT_MAPS + o)] * lcl_bot[w];
							}
						}
#endif

			} // for(; og < (MLO_N_OUT_BLK_GRP; ++og )

			barrier(CLK_LOCAL_MEM_FENCE);

// move data up
			for(int c_scan = c_scan0; c_scan < MLO_FILTER_SIZE1 -1; c_scan += MLO_IN_VERT_READS)
			{
					*(MLO_READ_TYPE*)in_rd_data = *(MLO_READ_TYPE*)&lcl_bot[(c_scan +  (MLO_IN_LCL_HEIGHT - MLO_FILTER_SIZE1 + 1))*(MLO_IN_LCL_WIDTH) + MLO_FILTER_PAD0 + c_pix4*MLO_READ_UNIT];
					*(MLO_READ_TYPE*)&lcl_bot[c_scan*(MLO_IN_LCL_WIDTH) + MLO_FILTER_PAD0 + c_pix4*MLO_READ_UNIT] = *(MLO_READ_TYPE*)in_rd_data;

			}

		} // for (int ob = 0; ob < MLO_N_OUT_BLK; ++ob, in_y += (MLO_IN_LCL_HEIGHT - MLO_FILTER_SIZE1 + 1), out_y += MLO_N_ALIGNED_OUT_SCAN_BLK)
	} // for (int b = 0;

#endif

	int oo = iDiv(lcl_id, (MLO_FILTER_SIZE1*MLO_FILTER_SIZE0));
	int wei_i = iMod(lcl_id, oo, (MLO_FILTER_SIZE1*MLO_FILTER_SIZE0));
	int wei_i_y = iDiv(wei_i, (MLO_FILTER_SIZE0));
	int wei_i_x = iMod(wei_i,wei_i_y, (MLO_FILTER_SIZE0));
	// send it out
	int wei_df_off = mul24(o_idx, (int)MLO_WEI_BATCH_STRIDE)
		// this input channel
		+ mul24(c_idx, (int)MLO_WEI_CHANNEL_STRIDE);

	int wei_lcl_off = 0;
	_FLOAT final_sum = 0;

// save in lcl and orgnize in a proper order
// outputs
//	filter size1
//	  filter size0
// TO DO DEPENDING ON THE GROUP SIZE
	for(int og = 0; og < MLO_N_OUT_BLK_GRP; ++og)
	{
		for(int o = 0;  w_blk_idx < MLO_MAX_WEI_BLK_LOOP/* && lcl_id < MLO_OUT_WEI_SCAN_BLK * MLO_MAX_WEI_BLK_LOOP * MLO_WEI_BLK_SZ0 * MLO_WEI_WKITEM*/ && o < MLO_N_LCL_OUT_MAPS; ++o)
		{
			int w = 0;
			for(; w < MLO_WEI_WKITEM; ++w)
			{
// save "virtual" filter table
				int w_x = w_x0 + w*MLO_WEI_BLK_SZ0;
				wei_lcl_off = ((o * MLO_MAX_WEI_BLK_LOOP + w_blk_idx) * MLO_FILTER_SIZE1  + w_y) * (MLO_WEI_BLK_SZ0 *MLO_WEI_WKITEM) + w_x;
				lcl_bot[wei_lcl_off] = pvt_accum[(og * MLO_N_LCL_OUT_MAPS + o) * MLO_WEI_WKITEM + w];
#if 0
				// wei_lcl_off == 1020 || wei_lcl_off == 1080 || wei_lcl_off == 1140)
				if (c_idx == 0 && o_idx == 0 && og == 0 && o == 0 && w_y == 1 && w_x == 1/* && lcl_id < MLO_OUT_WEI_SCAN_BLK * MLO_MAX_WEI_BLK_LOOP * MLO_WEI_BLK_SZ0 * MLO_WEI_WKITEM*/)
				{
					printf("K:u: %d %d %d %f %f\n",
						lcl_id,
						w_blk_idx,
						wei_lcl_off,
						lcl_bot[wei_lcl_off],
						pvt_accum[(og * MLO_N_LCL_OUT_MAPS + o) * MLO_WEI_WKITEM + w]
					);
				}
#endif

			}

		}

		barrier(CLK_LOCAL_MEM_FENCE);
#if 1
// read into real filter table

		if (lcl_id < ( MLO_N_LCL_OUT_MAPS *MLO_FILTER_SIZE1*MLO_FILTER_SIZE0))
		{
			final_sum = 0;
			for(int i = 0; i < MLO_MAX_WEI_BLK_LOOP; ++i)
			{
				final_sum += lcl_bot[((oo * MLO_MAX_WEI_BLK_LOOP + i) * MLO_FILTER_SIZE1 + wei_i_y) * (MLO_WEI_BLK_SZ0 *MLO_WEI_WKITEM) + wei_i_x];
#if 0
				if (c_idx == 0 && o_idx == 0  && og == 0 && oo  == 0 && wei_i_y == 1 && wei_i_x == 1)
				{
					printf("K:fs: %d %d %d  %f %f\n",
						lcl_id,
						i,
						((oo * MLO_MAX_WEI_BLK_LOOP + i) * MLO_FILTER_SIZE1 + wei_i_y) * (MLO_WEI_BLK_SZ0 *MLO_WEI_WKITEM) + wei_i_x,
						final_sum,
						lcl_bot[((oo * MLO_MAX_WEI_BLK_LOOP + i) * MLO_FILTER_SIZE1 + wei_i_y) * (MLO_WEI_BLK_SZ0 *MLO_WEI_WKITEM) + wei_i_x]
					);
				}
#endif
			}

#if 1

			weights_df[wei_df_off + (og *  MLO_N_LCL_OUT_MAPS + oo) * MLO_WEI_BATCH_STRIDE + wei_i] = final_sum; //lcl_bot[lcl_id]; //

#if 0
			if (og == 1 && oo == 0 && wei_i == 0)
			{

				printf("K:o: %d %d %f\n",
					wei_df_off,
					wei_df_off + (og *  MLO_N_LCL_OUT_MAPS + oo) * MLO_WEI_BATCH_STRIDE + wei_i,
					weights_df[wei_df_off + (og *  MLO_N_LCL_OUT_MAPS + oo) * MLO_WEI_BATCH_STRIDE + wei_i]
					);
			}
#endif
#else
			_FLOAT t_accum = 0;

			for (int og = 0; og < MLO_N_OUT_BLK_GRP; ++og)
			{
				for (int o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
				{
					for (int w = 0; w < MLO_WEI_WKITEM; ++w)
					{
						t_accum += pvt_accum[(og * MLO_N_LCL_OUT_MAPS + o) * MLO_WEI_WKITEM + w];
					}
				}
			}

			weights_df[lcl_id] = t_accum;
#endif

		}
#endif
		barrier(CLK_LOCAL_MEM_FENCE);

	} // for(int og = 0; og < MLO_N_OUT_BLK_GRP; ++og)

}


tweaking argmaxhacked.cl

tweaking argmaxhacked.cl

struct class_Eigen__array {
    int f0[1];
};
struct Eigen__Tuple {
    int f0;
    float f1;
};
struct Eigen__DSizes {
    struct class_Eigen__array f0;
};
struct Eigen__TensorEvaluator_0 {
    global int* f0;
    struct Eigen__DSizes f1;
    global struct Eigen__GpuDevice* f2;
    global struct class_Eigen__TensorMap* f3;
};
struct Eigen__GpuDevice {
    global struct class_Eigen__StreamInterface* f0;
    int f1;
    char f2[4];
};
struct class_Eigen__TensorMap {
    global int* f0;
    struct Eigen__DSizes f1;
    char f2[4];
};
struct class_Eigen__StreamInterface {
};
struct Eigen__TensorEvaluator_4 {
    global float* f0;
    struct Eigen__DSizes f1;
    global struct Eigen__GpuDevice* f2;
    global struct class_Eigen__TensorMap_5* f3;
};
struct class_Eigen__TensorMap_5 {
    global float* f0;
    struct Eigen__DSizes f1;
    char f2[4];
};
struct class_Eigen__array_nopointers {
    int f0[1];
};
struct Eigen__DSizes_nopointers {
    struct class_Eigen__array_nopointers f0;
};
struct Eigen__TensorEvaluator_0_nopointers {
    struct Eigen__DSizes_nopointers f0;
};
struct Eigen__TensorEvaluator_3 {
    struct Eigen__TensorEvaluator_4 f0;
};
struct class_Eigen__array_10 {
    char f0[1];
};
struct Eigen__Sizes {
    char f0;
};
struct Eigen__TensorEvaluator_4_nopointers {
    struct Eigen__DSizes_nopointers f0;
};
struct Eigen__TensorEvaluator_3_nopointers {
    struct Eigen__TensorEvaluator_4_nopointers f0;
};
struct class_Eigen__array_11 {
    int f0;
};
struct Eigen__internal__ArgMaxTupleReducer {
    char f0;
};
struct class_Eigen__array_10_nopointers {
    char f0[1];
};
struct Eigen__TensorEvaluator_9 {
    struct class_Eigen__array_10 f0;
    struct Eigen__Sizes f1;
    struct class_Eigen__array_11 f2;
    struct class_Eigen__array f3;
    struct class_Eigen__array f4;
    struct class_Eigen__array f5;
    struct Eigen__TensorEvaluator_3 f6;
    struct Eigen__internal__ArgMaxTupleReducer f7;
    global struct Eigen__Tuple* f8;
    global struct Eigen__GpuDevice* f9;
};
struct Eigen__Sizes_nopointers {
    char f0;
};
struct Eigen__TensorEvaluator_2 {
    struct Eigen__TensorEvaluator_3 f0;
    struct Eigen__TensorEvaluator_9 f1;
    int f2;
    struct class_Eigen__array f3;
    int f4;
    int f5;
};
struct class_Eigen__array_11_nopointers {
    int f0;
};
struct Eigen__TensorEvaluator {
    struct Eigen__TensorEvaluator_0 f0;
    struct Eigen__TensorEvaluator_2 f1;
};
struct Eigen__internal__ArgMaxTupleReducer_nopointers {
    char f0;
};
struct Eigen__TensorEvaluator_9_nopointers {
    struct class_Eigen__array_10_nopointers f0;
    struct Eigen__Sizes_nopointers f1;
    struct class_Eigen__array_11_nopointers f2;
    struct class_Eigen__array_nopointers f3;
    struct class_Eigen__array_nopointers f4;
    struct class_Eigen__array_nopointers f5;
    struct Eigen__TensorEvaluator_3_nopointers f6;
    struct Eigen__internal__ArgMaxTupleReducer_nopointers f7;
};
struct Eigen__TensorEvaluator_2_nopointers {
    struct Eigen__TensorEvaluator_3_nopointers f0;
    struct Eigen__TensorEvaluator_9_nopointers f1;
    int f2;
    struct class_Eigen__array_nopointers f3;
    int f4;
    int f5;
};
struct Eigen__TensorEvaluator_nopointers {
    struct Eigen__TensorEvaluator_0_nopointers f0;
    struct Eigen__TensorEvaluator_2_nopointers f1;
};

kernel void _ZN5Eigen8internal15EigenMetaKernelINS_15TensorEvaluatorIKNS_14TensorAssignOpINS_9TensorMapINS_6TensorIiLi1ELi1EiEELi16ENS_11MakePointerEEEKNS_20TensorTupleReducerOpINS0_18ArgMaxTupleReducerINS_5TupleIifEEEEKNS_5arrayIiLm1EEEKNS4_INS5_IfLi1ELi1EiEELi16ES7_EEEEEENS_9GpuDeviceEEEiEEvT_T0_(global struct Eigen__TensorEvaluator_nopointers* eval_nopointers, global int* eval_ptr0, uint eval_ptr0_offset, global float* eval_ptr1, uint eval_ptr1_offset, global float* eval_ptr2, uint eval_ptr2_offset, int size, local int *scratch);

kernel void _ZN5Eigen8internal15EigenMetaKernelINS_15TensorEvaluatorIKNS_14TensorAssignOpINS_9TensorMapINS_6TensorIiLi1ELi1EiEELi16ENS_11MakePointerEEEKNS_20TensorTupleReducerOpINS0_18ArgMaxTupleReducerINS_5TupleIifEEEEKNS_5arrayIiLm1EEEKNS4_INS5_IfLi1ELi1EiEELi16ES7_EEEEEENS_9GpuDeviceEEEiEEvT_T0_(global struct Eigen__TensorEvaluator_nopointers* eval_nopointers, global int* eval_ptr0, uint eval_ptr0_offset, global float* eval_ptr1, uint eval_ptr1_offset, global float* eval_ptr2, uint eval_ptr2_offset, int size, local int *scratch) {
    eval_ptr2 += eval_ptr2_offset;
    eval_ptr1 += eval_ptr1_offset;
    eval_ptr0 += eval_ptr0_offset;
struct Eigen__TensorEvaluator eval[1];
eval[0].f0.f1.f0.f0[0] = eval_nopointers[0].f0.f0.f0.f0[0];
eval[0].f1.f0.f0.f1.f0.f0[0] = eval_nopointers[0].f1.f0.f0.f0.f0.f0[0];
eval[0].f1.f1.f0.f0[0] = eval_nopointers[0].f1.f1.f0.f0[0];
eval[0].f1.f1.f1.f0 = eval_nopointers[0].f1.f1.f1.f0;
eval[0].f1.f1.f2.f0 = eval_nopointers[0].f1.f1.f2.f0;
eval[0].f1.f1.f3.f0[0] = eval_nopointers[0].f1.f1.f3.f0[0];
eval[0].f1.f1.f4.f0[0] = eval_nopointers[0].f1.f1.f4.f0[0];
eval[0].f1.f1.f5.f0[0] = eval_nopointers[0].f1.f1.f5.f0[0];
eval[0].f1.f1.f6.f0.f1.f0.f0[0] = eval_nopointers[0].f1.f1.f6.f0.f0.f0.f0[0];
eval[0].f1.f1.f7.f0 = eval_nopointers[0].f1.f1.f7.f0;
eval[0].f1.f2 = eval_nopointers[0].f1.f2;
eval[0].f1.f3.f0[0] = eval_nopointers[0].f1.f3.f0[0];
eval[0].f1.f4 = eval_nopointers[0].f1.f4;
eval[0].f1.f5 = eval_nopointers[0].f1.f5;
eval[0].f0.f0 = eval_ptr0;
eval[0].f1.f0.f0.f0 = eval_ptr1;
eval[0].f1.f1.f6.f0.f0 = eval_ptr2;

    bool v103;
    bool v111;
    bool v70;
    bool v86;
    bool v94;
    float v102;
    float v105;
    float v110;
    float v113;
    float v60;
    float max_so_far;
    float v69;
    float new_max_so_far;
    float v80;
    float v85;
    float v88;
    float v93;
    float v96;
    global float* input_data;
    global int* v126;
    global int* output_data;
    global struct Eigen__Tuple* v36;
    int v107;
    int v112;
    int v114;
    int v117;
    int v124;
    int v128;
    int group_id;
    int local_size;
    int local_id;
    int global_id;
    int num_groups;
    int inner_size;
    int v43;
    int inner_size_mod4;
    int global_pos;
    int v55;
    int v56;
    int segment_offset;
    int v58;
    int v61;
    int idx;
    int best_pos_so_far;
    int count;
    int candidate_pos;
    int new_best_pos_so_far;
    int new_idx;
    int new_count;
    int v77;
    int v78;
    int v79;
    int v81;
    int v82;
    int v90;
    int v99;
    int* v34;
    long v118;

    /* int group_id = call <unk> */;
    group_id = get_group_id(0);
    /* int local_size = call <unk> */;
    local_size = get_local_size(0);
    /* int v22 = mul local_size group_id */;
    /* int local_id = call <unk> */;
    local_id = get_local_id(0);
    /* int global_id = add v22 local_id */;
    global_id = (local_size * group_id) + local_id;
    /* int num_groups = call <unk> */;
    num_groups = get_num_groups(0);
    /* int v26 = mul num_groups local_size */;
    /* bool v27 = icmp global_id size */;
    /* if(v27) */
    if (global_id >= size) {
        goto exit;
    }

    /* struct Eigen__Tuple** v28 = getelementptr eval <unk> <unk> <unk> <unk> */;
    /* int* v30 = getelementptr eval v29 <unk> <unk> <unk> <unk> v29 */;
    /* float** v31 = getelementptr eval v29 <unk> <unk> <unk> <unk> <unk> */;
    /* int* v32 = getelementptr eval v29 <unk> <unk> */;
    /* int** v33 = getelementptr eval v29 <unk> <unk> */;
    /* int* v34 = getelementptr eval v29 <unk> <unk> */;
    v34 = eval[0].f1.f4;
    /* long* v35 = bitcast v34 */;
    /* struct Eigen__Tuple* v36 = load v28 */;
    v36 = eval[0].f1.f1.f8;
    /* bool v37 = icmp v36 <unk> */;
    /* int inner_size = load v30 */;
    inner_size = eval[0].f1.f1.f3.f0;
    /* bool v40 = icmp inner_size <unk> */;
    /* float* input_data = load v31 */;
    input_data = eval_ptr2;
    /* int v43 = load v32 */;
    v43 = eval[0].f1.f2;
    /* bool v44 = icmp v43 0 */;
    /* int* output_data = load v33 */;
    output_data = eval_ptr0;
    /* int v46 = add inner_size <unk> */;
    /* int inner_size_mod4 = and inner_size <unk> */;
    inner_size_mod4 = inner_size & 3;
    /* bool v50 = icmp inner_size_mod4 0 */;
    /* bool v51 = icmp v46 v49 */;
    /* int global_pos = phi global_id */
    global_pos = global_id;

block3:;
    /* if(v37) */
    if (v36 == 0) {
        goto block5;
    }

    /* long v53 = sext global_pos */;
    /* int* v54 = getelementptr v36 v53 0 */;
    /* int v55 = load v54 */;
    v56 = v36[global_pos].f0;
    /* int v56 = phi v55 */
    // v56 = v55;
    goto block15;
block5:;
    /* int segment_offset = mul inner_size global_pos */;
    segment_offset = inner_size * global_pos;
    /* if(v40) */
    if (inner_size <= 0) {
        /* int v56 = phi 0 */
        v56 = 0;
        goto block15;
    }

    /* if(v50) */
    if (inner_size_mod4 == 0) {
        /* int v58 = phi 0 */
        v58 = 0;
        /* float v60 = phi -INFINITY */
        v60 = -INFINITY;
        /* int v61 = phi 0 */
        v61 = 0;
        goto block10;
    }

    /* int idx = phi 0 */
    idx = 0;
    /* float max_so_far = phi -INFINITY */
    max_so_far = -INFINITY;
    /* int best_pos_so_far = phi 0 */
    best_pos_so_far = 0;
    /* int count = phi inner_size_mod4 */
    count = inner_size_mod4;

block8:;
    /* int candidate_pos = add idx segment_offset */;
    candidate_pos = idx + segment_offset;
    /* long v67 = sext candidate_pos */;
    /* float* v68 = getelementptr input_data v67 */;
    /* float v69 = load v68 */;
    // v69 = input_data[candidate_pos];
    /* bool v70 = fcmp v69 max_so_far */;
    // v70 = v69 <= max_so_far;
    /* int new_best_pos_so_far = select v70 best_pos_so_far candidate_pos */;
    new_best_pos_so_far = input_data[candidate_pos] <= max_so_far ? best_pos_so_far : candidate_pos;
    /* float new_max_so_far = select v70 max_so_far v69 */;
    new_max_so_far = input_data[candidate_pos] <= max_so_far ? max_so_far : input_data[candidate_pos];
    /* int new_idx = add idx <unk> */;
    new_idx = idx + 1;
    /* int new_count = add count v47 */;
    new_count = count - 1;
    /* bool v76 = icmp new_count 0 */;
    /* if(v76) */
    if(new_count != 0) {
        /* int idx = phi new_idx */
        idx = new_idx;
        /* float max_so_far = phi new_max_so_far */
        max_so_far = new_max_so_far;
        /* int best_pos_so_far = phi new_best_pos_so_far */
        best_pos_so_far = new_best_pos_so_far;
        /* int count = phi new_count */
        count = new_count;
        goto block8;
    }

    /* int v77 = phi new_best_pos_so_far */
    v77 = new_best_pos_so_far;
    /* int v58 = phi new_idx */
    v58 = new_idx;
    /* float v60 = phi new_max_so_far */
    v60 = new_max_so_far;
    /* int v61 = phi new_best_pos_so_far */
    v61 = new_best_pos_so_far;

block10:;
    /* if(v51) */
    if (inner_size < 4) {
        /* int v78 = phi v77 */
        v78 = v77;
        goto block14;
    }

    /* int v79 = phi v58 */
    v79 = v58;
    /* float v80 = phi v60 */
    v80 = v60;
    /* int v81 = phi v61 */
    v81 = v61;

block12:;
    /* int v82 = add v79 segment_offset */;
    v82 = v79 + segment_offset;
    /* long v83 = sext v82 */;
    /* float* v84 = getelementptr input_data v83 */;
    /* float v85 = load v84 */;
    v85 = (&(input_data[v82]))[0];
    /* bool v86 = fcmp v85 v80 */;
    v86 = v85 <= v80;
    /* int v87 = select v86 v81 v82 */;
    /* float v88 = select v86 v80 v85 */;
    v88 = v86 ? v80 : v85;
    /* int v89 = add v79 v74 */;
    /* int v90 = add v89 segment_offset */;
    v90 = (v79 + 1) + segment_offset;
    /* long v91 = sext v90 */;
    /* float* v92 = getelementptr input_data v91 */;
    /* float v93 = load v92 */;
    v93 = (&(input_data[v90]))[0];
    /* bool v94 = fcmp v93 v88 */;
    v94 = v93 <= v88;
    /* int v95 = select v94 v87 v90 */;
    /* float v96 = select v94 v88 v93 */;
    v96 = v94 ? v88 : v93;
    /* int v97 = add v79 <unk> */;
    /* int v99 = add v97 segment_offset */;
    v99 = (v79 + 2) + segment_offset;
    /* long v100 = sext v99 */;
    /* float* v101 = getelementptr input_data v100 */;
    /* float v102 = load v101 */;
    v102 = (&(input_data[v99]))[0];
    /* bool v103 = fcmp v102 v96 */;
    v103 = v102 <= v96;
    /* int v104 = select v103 v95 v99 */;
    /* float v105 = select v103 v96 v102 */;
    v105 = v103 ? v96 : v102;
    /* int v106 = add v79 v49 */;
    /* int v107 = add v106 segment_offset */;
    v107 = (v79 + 3) + segment_offset;
    /* long v108 = sext v107 */;
    /* float* v109 = getelementptr input_data v108 */;
    /* float v110 = load v109 */;
    v110 = (&(input_data[v107]))[0];
    /* bool v111 = fcmp v110 v105 */;
    v111 = v110 <= v105;
    /* int v112 = select v111 v104 v107 */;
    v112 = v111 ? (v103 ? (v94 ? (v86 ? v81 : v82) : v90) : v99) : v107;
    /* float v113 = select v111 v105 v110 */;
    v113 = v111 ? v105 : v110;
    /* int v114 = add v79 <unk> */;
    v114 = v79 + 4;
    /* bool v116 = icmp v114 inner_size */;
    /* if(v116) */
    if(v114 != inner_size) {
        /* int v79 = phi v114 */
        v79 = v114;
        /* float v80 = phi v113 */
        v80 = v113;
        /* int v81 = phi v112 */
        v81 = v112;
        goto block12;
    }

    /* int v78 = phi v112 */
    v78 = v112;

block14:;
    /* int v56 = phi v78 */
    v56 = v78;

block15:;
    /* if(v44) */
    if (v43 < 0) {
        /* int v117 = phi v56 */
        v117 = v56;
        goto block17;
    }

    /* long v118 = load v35 */;
    v118 = ((long*)v34)[0];
    /* int v119 = trunc v118 */;
    /* int v120 = srem v56 v119 */;
    /* long v121 = lshr v118 <unk> */;
    /* int v123 = trunc v121 */;
    /* int v124 = sdiv v120 v123 */;
    v124 = (v56 % (int)v118) / (int)(v118 >> 32);
    /* int v117 = phi v124 */
    v117 = v124;

block17:;
    /* long v125 = sext global_pos */;
    /* int* v126 = getelementptr output_data v125 */;
    //v126 = &output_data[global_pos];
    /* void v127 = store v117 v126 */;
    output_data[global_pos] = v117;
    /* int v128 = add global_pos v26 */;
    global_pos += (num_groups * local_size);
    /* bool v129 = icmp v128 size */;
    /* if(v129) */
    if (global_pos < size) {
        /* int global_pos = phi v128 */
        goto block3;
    }
v18:;
exit:;
    return;
}

struct class_Eigen__array {
    int f0[1];
};
struct Eigen__Tuple {
    int f0;
    float f1;
};
struct Eigen__DSizes {
    struct class_Eigen__array f0;
};
struct Eigen__TensorEvaluator_0 {
    global int* f0;
    struct Eigen__DSizes f1;
    global struct Eigen__GpuDevice* f2;
    global struct class_Eigen__TensorMap* f3;
};
struct Eigen__GpuDevice {
    global struct class_Eigen__StreamInterface* f0;
    int f1;
    char f2[4];
};
struct class_Eigen__TensorMap {
    global int* f0;
    struct Eigen__DSizes f1;
    char f2[4];
};
struct class_Eigen__StreamInterface {
};
struct Eigen__TensorEvaluator_4 {
    global float* f0;
    struct Eigen__DSizes f1;
    global struct Eigen__GpuDevice* f2;
    global struct class_Eigen__TensorMap_5* f3;
};
struct class_Eigen__TensorMap_5 {
    global float* f0;
    struct Eigen__DSizes f1;
    char f2[4];
};
struct class_Eigen__array_nopointers {
    int f0[1];
};
struct Eigen__DSizes_nopointers {
    struct class_Eigen__array_nopointers f0;
};
struct Eigen__TensorEvaluator_0_nopointers {
    struct Eigen__DSizes_nopointers f0;
};
struct Eigen__TensorEvaluator_3 {
    struct Eigen__TensorEvaluator_4 f0;
};
struct class_Eigen__array_10 {
    char f0[1];
};
struct Eigen__Sizes {
    char f0;
};
struct Eigen__TensorEvaluator_4_nopointers {
    struct Eigen__DSizes_nopointers f0;
};
struct Eigen__TensorEvaluator_3_nopointers {
    struct Eigen__TensorEvaluator_4_nopointers f0;
};
struct class_Eigen__array_11 {
    int f0;
};
struct Eigen__internal__ArgMaxTupleReducer {
    char f0;
};
struct class_Eigen__array_10_nopointers {
    char f0[1];
};
struct Eigen__TensorEvaluator_9 {
    struct class_Eigen__array_10 f0;
    struct Eigen__Sizes f1;
    struct class_Eigen__array_11 f2;
    struct class_Eigen__array f3;
    struct class_Eigen__array f4;
    struct class_Eigen__array f5;
    struct Eigen__TensorEvaluator_3 f6;
    struct Eigen__internal__ArgMaxTupleReducer f7;
    global struct Eigen__Tuple* f8;
    global struct Eigen__GpuDevice* f9;
};
struct Eigen__Sizes_nopointers {
    char f0;
};
struct Eigen__TensorEvaluator_2 {
    struct Eigen__TensorEvaluator_3 f0;
    struct Eigen__TensorEvaluator_9 f1;
    int f2;
    struct class_Eigen__array f3;
    int f4;
    int f5;
};
struct class_Eigen__array_11_nopointers {
    int f0;
};
struct Eigen__TensorEvaluator {
    struct Eigen__TensorEvaluator_0 f0;
    struct Eigen__TensorEvaluator_2 f1;
};
struct Eigen__internal__ArgMaxTupleReducer_nopointers {
    char f0;
};
struct Eigen__TensorEvaluator_9_nopointers {
    struct class_Eigen__array_10_nopointers f0;
    struct Eigen__Sizes_nopointers f1;
    struct class_Eigen__array_11_nopointers f2;
    struct class_Eigen__array_nopointers f3;
    struct class_Eigen__array_nopointers f4;
    struct class_Eigen__array_nopointers f5;
    struct Eigen__TensorEvaluator_3_nopointers f6;
    struct Eigen__internal__ArgMaxTupleReducer_nopointers f7;
};
struct Eigen__TensorEvaluator_2_nopointers {
    struct Eigen__TensorEvaluator_3_nopointers f0;
    struct Eigen__TensorEvaluator_9_nopointers f1;
    int f2;
    struct class_Eigen__array_nopointers f3;
    int f4;
    int f5;
};
struct Eigen__TensorEvaluator_nopointers {
    struct Eigen__TensorEvaluator_0_nopointers f0;
    struct Eigen__TensorEvaluator_2_nopointers f1;
};

kernel void _ZN5Eigen8internal15EigenMetaKernelINS_15TensorEvaluatorIKNS_14TensorAssignOpINS_9TensorMapINS_6TensorIiLi1ELi1EiEELi16ENS_11MakePointerEEEKNS_20TensorTupleReducerOpINS0_18ArgMaxTupleReducerINS_5TupleIifEEEEKNS_5arrayIiLm1EEEKNS4_INS5_IfLi1ELi1EiEELi16ES7_EEEEEENS_9GpuDeviceEEEiEEvT_T0_(global struct Eigen__TensorEvaluator_nopointers* eval_nopointers, global int* eval_ptr0, uint eval_ptr0_offset, global float* eval_ptr1, uint eval_ptr1_offset, global float* eval_ptr2, uint eval_ptr2_offset, int size, local int *scratch);

kernel void _ZN5Eigen8internal15EigenMetaKernelINS_15TensorEvaluatorIKNS_14TensorAssignOpINS_9TensorMapINS_6TensorIiLi1ELi1EiEELi16ENS_11MakePointerEEEKNS_20TensorTupleReducerOpINS0_18ArgMaxTupleReducerINS_5TupleIifEEEEKNS_5arrayIiLm1EEEKNS4_INS5_IfLi1ELi1EiEELi16ES7_EEEEEENS_9GpuDeviceEEEiEEvT_T0_(global struct Eigen__TensorEvaluator_nopointers* eval_nopointers, global int* eval_ptr0, uint eval_ptr0_offset, global float* eval_ptr1, uint eval_ptr1_offset, global float* eval_ptr2, uint eval_ptr2_offset, int size, local int *scratch) {
    eval_ptr2 += eval_ptr2_offset;
    eval_ptr1 += eval_ptr1_offset;
    eval_ptr0 += eval_ptr0_offset;
struct Eigen__TensorEvaluator eval[1];
eval[0].f0.f1.f0.f0[0] = eval_nopointers[0].f0.f0.f0.f0[0];
eval[0].f1.f0.f0.f1.f0.f0[0] = eval_nopointers[0].f1.f0.f0.f0.f0.f0[0];
eval[0].f1.f1.f0.f0[0] = eval_nopointers[0].f1.f1.f0.f0[0];
eval[0].f1.f1.f1.f0 = eval_nopointers[0].f1.f1.f1.f0;
eval[0].f1.f1.f2.f0 = eval_nopointers[0].f1.f1.f2.f0;
eval[0].f1.f1.f3.f0[0] = eval_nopointers[0].f1.f1.f3.f0[0];
eval[0].f1.f1.f4.f0[0] = eval_nopointers[0].f1.f1.f4.f0[0];
eval[0].f1.f1.f5.f0[0] = eval_nopointers[0].f1.f1.f5.f0[0];
eval[0].f1.f1.f6.f0.f1.f0.f0[0] = eval_nopointers[0].f1.f1.f6.f0.f0.f0.f0[0];
eval[0].f1.f1.f7.f0 = eval_nopointers[0].f1.f1.f7.f0;
eval[0].f1.f2 = eval_nopointers[0].f1.f2;
eval[0].f1.f3.f0[0] = eval_nopointers[0].f1.f3.f0[0];
eval[0].f1.f4 = eval_nopointers[0].f1.f4;
eval[0].f1.f5 = eval_nopointers[0].f1.f5;
eval[0].f0.f0 = eval_ptr0;
eval[0].f1.f0.f0.f0 = eval_ptr1;
eval[0].f1.f1.f6.f0.f0 = eval_ptr2;

    bool v103;
    bool v111;
    bool v70;
    bool v86;
    bool v94;
    float v102;
    float v105;
    float v110;
    float v113;
    float v60;
    float max_so_far;
    float v69;
    float new_max_so_far;
    float v80;
    float v85;
    float v88;
    float v93;
    float v96;
    global float* input_data;
    global int* v126;
    global int* output_data;
    global struct Eigen__Tuple* v36;
    int v107;
    int v112;
    int v114;
    int v117;
    int v124;
    int v128;
    int group_id;
    int local_size;
    int local_id;
    int global_id;
    int num_groups;
    int inner_size;
    int v43;
    int inner_size_mod4;
    int global_pos;
    int v55;
    int v56;
    int segment_offset;
    int v58;
    int v61;
    int idx;
    int best_pos_so_far;
    int count;
    int candidate_pos;
    int new_best_pos_so_far;
    int new_idx;
    int new_count;
    int v77;
    int v78;
    int v79;
    int v81;
    int v82;
    int v90;
    int v99;
    int* v34;
    long v118;

    /* int group_id = call <unk> */;
    group_id = get_group_id(0);
    /* int local_size = call <unk> */;
    local_size = get_local_size(0);
    /* int v22 = mul local_size group_id */;
    /* int local_id = call <unk> */;
    local_id = get_local_id(0);
    /* int global_id = add v22 local_id */;
    global_id = (local_size * group_id) + local_id;
    /* int num_groups = call <unk> */;
    num_groups = get_num_groups(0);
    /* int v26 = mul num_groups local_size */;
    /* bool v27 = icmp global_id size */;
    /* if(v27) */
    if (global_id >= size) {
        goto exit;
    }

    /* struct Eigen__Tuple** v28 = getelementptr eval <unk> <unk> <unk> <unk> */;
    /* int* v30 = getelementptr eval v29 <unk> <unk> <unk> <unk> v29 */;
    /* float** v31 = getelementptr eval v29 <unk> <unk> <unk> <unk> <unk> */;
    /* int* v32 = getelementptr eval v29 <unk> <unk> */;
    /* int** v33 = getelementptr eval v29 <unk> <unk> */;
    /* int* v34 = getelementptr eval v29 <unk> <unk> */;
    v34 = eval[0].f1.f4;
    /* long* v35 = bitcast v34 */;
    /* struct Eigen__Tuple* v36 = load v28 */;
    v36 = eval[0].f1.f1.f8;
    /* bool v37 = icmp v36 <unk> */;
    /* int inner_size = load v30 */;
    inner_size = eval[0].f1.f1.f3.f0;
    /* bool v40 = icmp inner_size <unk> */;
    /* float* input_data = load v31 */;
    input_data = eval_ptr2;
    /* int v43 = load v32 */;
    v43 = (&(eval[0].f1.f2))[0];
    /* bool v44 = icmp v43 0 */;
    /* int* output_data = load v33 */;
    output_data = eval_ptr0;
    /* int v46 = add inner_size <unk> */;
    /* int inner_size_mod4 = and inner_size <unk> */;
    inner_size_mod4 = inner_size & 3;
    /* bool v50 = icmp inner_size_mod4 0 */;
    /* bool v51 = icmp v46 v49 */;
    /* int global_pos = phi global_id */
    global_pos = global_id;

block3:;
    /* if(v37) */
    if (v36 == 0) {
        goto block5;
    }

    /* long v53 = sext global_pos */;
    /* int* v54 = getelementptr v36 v53 0 */;
    /* int v55 = load v54 */;
    v56 = v36[global_pos].f0;
    /* int v56 = phi v55 */
    // v56 = v55;
    goto block15;
block5:;
    /* int segment_offset = mul inner_size global_pos */;
    segment_offset = inner_size * global_pos;
    /* if(v40) */
    if (inner_size <= 0) {
        /* int v56 = phi 0 */
        v56 = 0;
        goto block15;
    }

    /* if(v50) */
    if (inner_size_mod4 == 0) {
        /* int v58 = phi 0 */
        v58 = 0;
        /* float v60 = phi -INFINITY */
        v60 = -INFINITY;
        /* int v61 = phi 0 */
        v61 = 0;
        goto block10;
    }

    /* int idx = phi 0 */
    idx = 0;
    /* float max_so_far = phi -INFINITY */
    max_so_far = -INFINITY;
    /* int best_pos_so_far = phi 0 */
    best_pos_so_far = 0;
    /* int count = phi inner_size_mod4 */
    count = inner_size_mod4;

block8:;
    /* int candidate_pos = add idx segment_offset */;
    candidate_pos = idx + segment_offset;
    /* long v67 = sext candidate_pos */;
    /* float* v68 = getelementptr input_data v67 */;
    /* float v69 = load v68 */;
    // v69 = input_data[candidate_pos];
    /* bool v70 = fcmp v69 max_so_far */;
    // v70 = v69 <= max_so_far;
    /* int new_best_pos_so_far = select v70 best_pos_so_far candidate_pos */;
    new_best_pos_so_far = input_data[candidate_pos] <= max_so_far ? best_pos_so_far : candidate_pos;
    /* float new_max_so_far = select v70 max_so_far v69 */;
    new_max_so_far = input_data[candidate_pos] <= max_so_far ? max_so_far : input_data[candidate_pos];
    /* int new_idx = add idx <unk> */;
    new_idx = idx + 1;
    /* int new_count = add count v47 */;
    new_count = count - 1;
    /* bool v76 = icmp new_count 0 */;
    /* if(v76) */
    if(new_count != 0) {
        /* int idx = phi new_idx */
        idx = new_idx;
        /* float max_so_far = phi new_max_so_far */
        max_so_far = new_max_so_far;
        /* int best_pos_so_far = phi new_best_pos_so_far */
        best_pos_so_far = new_best_pos_so_far;
        /* int count = phi new_count */
        count = new_count;
        goto block8;
    }

    /* int v77 = phi new_best_pos_so_far */
    v77 = new_best_pos_so_far;
    /* int v58 = phi new_idx */
    v58 = new_idx;
    /* float v60 = phi new_max_so_far */
    v60 = new_max_so_far;
    /* int v61 = phi new_best_pos_so_far */
    v61 = new_best_pos_so_far;

block10:;
    /* if(v51) */
    if (inner_size < 4) {
        /* int v78 = phi v77 */
        v78 = v77;
        goto block14;
    }

    /* int v79 = phi v58 */
    v79 = v58;
    /* float v80 = phi v60 */
    v80 = v60;
    /* int v81 = phi v61 */
    v81 = v61;

block12:;
    /* int v82 = add v79 segment_offset */;
    v82 = v79 + segment_offset;
    /* long v83 = sext v82 */;
    /* float* v84 = getelementptr input_data v83 */;
    /* float v85 = load v84 */;
    v85 = (&(input_data[v82]))[0];
    /* bool v86 = fcmp v85 v80 */;
    v86 = v85 <= v80;
    /* int v87 = select v86 v81 v82 */;
    /* float v88 = select v86 v80 v85 */;
    v88 = v86 ? v80 : v85;
    /* int v89 = add v79 v74 */;
    /* int v90 = add v89 segment_offset */;
    v90 = (v79 + 1) + segment_offset;
    /* long v91 = sext v90 */;
    /* float* v92 = getelementptr input_data v91 */;
    /* float v93 = load v92 */;
    v93 = (&(input_data[v90]))[0];
    /* bool v94 = fcmp v93 v88 */;
    v94 = v93 <= v88;
    /* int v95 = select v94 v87 v90 */;
    /* float v96 = select v94 v88 v93 */;
    v96 = v94 ? v88 : v93;
    /* int v97 = add v79 <unk> */;
    /* int v99 = add v97 segment_offset */;
    v99 = (v79 + 2) + segment_offset;
    /* long v100 = sext v99 */;
    /* float* v101 = getelementptr input_data v100 */;
    /* float v102 = load v101 */;
    v102 = (&(input_data[v99]))[0];
    /* bool v103 = fcmp v102 v96 */;
    v103 = v102 <= v96;
    /* int v104 = select v103 v95 v99 */;
    /* float v105 = select v103 v96 v102 */;
    v105 = v103 ? v96 : v102;
    /* int v106 = add v79 v49 */;
    /* int v107 = add v106 segment_offset */;
    v107 = (v79 + 3) + segment_offset;
    /* long v108 = sext v107 */;
    /* float* v109 = getelementptr input_data v108 */;
    /* float v110 = load v109 */;
    v110 = (&(input_data[v107]))[0];
    /* bool v111 = fcmp v110 v105 */;
    v111 = v110 <= v105;
    /* int v112 = select v111 v104 v107 */;
    v112 = v111 ? (v103 ? (v94 ? (v86 ? v81 : v82) : v90) : v99) : v107;
    /* float v113 = select v111 v105 v110 */;
    v113 = v111 ? v105 : v110;
    /* int v114 = add v79 <unk> */;
    v114 = v79 + 4;
    /* bool v116 = icmp v114 inner_size */;
    /* if(v116) */
    if(v114 != inner_size) {
        /* int v79 = phi v114 */
        v79 = v114;
        /* float v80 = phi v113 */
        v80 = v113;
        /* int v81 = phi v112 */
        v81 = v112;
        goto block12;
    }

    /* int v78 = phi v112 */
    v78 = v112;

block14:;
    /* int v56 = phi v78 */
    v56 = v78;

block15:;
    /* if(v44) */
    if (v43 < 0) {
        /* int v117 = phi v56 */
        v117 = v56;
        goto block17;
    }

    /* long v118 = load v35 */;
    v118 = ((long*)v34)[0];
    /* int v119 = trunc v118 */;
    /* int v120 = srem v56 v119 */;
    /* long v121 = lshr v118 <unk> */;
    /* int v123 = trunc v121 */;
    /* int v124 = sdiv v120 v123 */;
    v124 = (v56 % (int)v118) / (int)(v118 >> 32);
    /* int v117 = phi v124 */
    v117 = v124;

block17:;
    /* long v125 = sext global_pos */;
    /* int* v126 = getelementptr output_data v125 */;
    //v126 = &output_data[global_pos];
    /* void v127 = store v117 v126 */;
    output_data[global_pos] = v117;
    /* int v128 = add global_pos v26 */;
    global_pos += (num_groups * local_size);
    /* bool v129 = icmp v128 size */;
    /* if(v129) */
    if (global_pos < size) {
        /* int global_pos = phi v128 */
        goto block3;
    }
v18:;
exit:;
    return;
}


Fixing copy paste error in sobel kernels in OpenCL backend

/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

T load2LocalMem(global const T * in,
               dim_type dim0, dim_type dim1,
               dim_type gx, dim_type gy,
               dim_type inStride1, dim_type inStride0)
{
    if (gx<0 || gx>=dim0 || gy<0 || gy>=dim1)
        return (T)0;
    else
        return in[gx*inStride0+gy*inStride1];
}

kernel
void sobel3x3(global T * dx,
              KParam     dxInfo,
              global T * dy,
              KParam     dyInfo,
              global const T * in,
              KParam     iInfo,
              local T *  localMem,
              dim_type nBBS)
{
    const dim_type radius  = 1;
    const dim_type padding = 2*radius;
    const dim_type shrdLen = get_local_size(0) + padding;

    unsigned batchId = get_group_id(0) / nBBS;
    global const T* iptr = in + (batchId * iInfo.strides[2] + iInfo.offset);
    global T*      dxptr = dx + (batchId * dxInfo.strides[2]);
    global T*      dyptr = dy + (batchId * dyInfo.strides[2]);

    dim_type lx = get_local_id(0);
    dim_type ly = get_local_id(1);

    dim_type gx = get_local_size(0) * (get_group_id(0)-batchId*nBBS) + lx;
    dim_type gy = get_local_size(1) * get_group_id(1) + ly;

    dim_type lx2 = lx + get_local_size(0);
    dim_type ly2 = ly + get_local_size(1);
    dim_type gx2 = gx + get_local_size(0);
    dim_type gy2 = gy + get_local_size(1);

    localMem[lx+shrdLen*ly] = load2LocalMem(iptr, iInfo.dims[0], iInfo.dims[1],
                                   gx-radius, gy-radius,
                                   iInfo.strides[1], iInfo.strides[0]);
    if (lx<padding) {
        localMem[lx2+shrdLen*ly] = load2LocalMem(iptr, iInfo.dims[0], iInfo.dims[1],
                                        gx2-radius, gy-radius,
                                        iInfo.strides[1], iInfo.strides[0]);
    }
    if (ly<padding) {
        localMem[lx+shrdLen*ly2] = load2LocalMem(iptr, iInfo.dims[0], iInfo.dims[1],
                                        gx-radius, gy2-radius,
                                        iInfo.strides[1], iInfo.strides[0]);
    }
    if (lx<padding && ly<padding) {
        localMem[lx2+shrdLen*ly2] = load2LocalMem(iptr, iInfo.dims[0], iInfo.dims[1],
                                         gx2-radius, gy2-radius,
                                         iInfo.strides[1], iInfo.strides[0]);
    }

    barrier(CLK_LOCAL_MEM_FENCE);

    if (gx < iInfo.dims[0] && gy < iInfo.dims[1]) {
        dim_type i = lx + radius;
        dim_type j = ly + radius;
        dim_type _i = i-1;
        dim_type i_ = i+1;
        dim_type _j = j-1;
        dim_type j_ = j+1;

        float NW = localMem[_i+shrdLen*_j];
        float SW = localMem[i_+shrdLen*_j];
        float NE = localMem[_i+shrdLen*j_];
        float SE = localMem[i_+shrdLen*j_];

        float t1 = localMem[i+shrdLen*_j];
        float t2 = localMem[i+shrdLen*j_];
        dxptr[gy*dxInfo.strides[1]+gx] = (T)(NW+SW - (NE+SE) + 2*(t1-t2));

        t1 = localMem[_i+shrdLen*j];
        t2 = localMem[i_+shrdLen*j];
        dyptr[gy*dyInfo.strides[1]+gx] = (T)(NW+NE - (SW+SE) + 2*(t1-t2));

    }
}

/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

T load2LocalMem(global const T * in,
               dim_type dim0, dim_type dim1,
               dim_type gx, dim_type gy,
               dim_type inStride1, dim_type inStride0)
{
    if (gx<0 || gx>=dim0 || gy<0 || gy>=dim1)
        return (T)0;
    else
        return in[gx*inStride0+gy*inStride1];
}

kernel
void sobel3x3(global T * dx,
              KParam     dxInfo,
              global T * dy,
              KParam     dyInfo,
              global const T * in,
              KParam     iInfo,
              local T *  localMem,
              dim_type nBBS)
{
    const dim_type radius  = 1;
    const dim_type padding = 2*radius;
    const dim_type shrdLen = get_local_size(0) + padding;

    unsigned batchId = get_group_id(0) / nBBS;
    global const T* iptr = in + (batchId * iInfo.strides[2] + iInfo.offset);
    global T*      dxptr = dx + (batchId * dxInfo.strides[2]);
    global T*      dyptr = dy + (batchId * dyInfo.strides[2]);

    dim_type lx = get_local_id(0);
    dim_type ly = get_local_id(1);

    dim_type gx = get_local_size(0) * (get_group_id(0)-batchId*nBBS) + lx;
    dim_type gy = get_local_size(1) * get_group_id(1) + ly;

    dim_type lx2 = lx + get_local_size(0);
    dim_type ly2 = ly + get_local_size(1);
    dim_type gx2 = gx + get_local_size(0);
    dim_type gy2 = gy + get_local_size(1);

    localMem[lx+shrdLen*ly] = load2LocalMem(iptr, iInfo.dims[0], iInfo.dims[1],
                                   gx-radius, gy-radius,
                                   iInfo.strides[1], iInfo.strides[0]);
    if (lx<padding) {
        localMem[lx2+shrdLen*ly] = load2LocalMem(iptr, iInfo.dims[0], iInfo.dims[1],
                                        gx2-radius, gy-radius,
                                        iInfo.strides[1], iInfo.strides[0]);
    }
    if (ly<padding) {
        localMem[lx+shrdLen*ly2] = load2LocalMem(iptr, iInfo.dims[0], iInfo.dims[1],
                                        gx-radius, gy2-radius,
                                        iInfo.strides[1], iInfo.strides[0]);
    }
    if (lx<padding && ly<padding) {
        localMem[lx2+shrdLen*ly2] = load2LocalMem(iptr, iInfo.dims[0], iInfo.dims[1],
                                         gx2-radius, gy2-radius,
                                         iInfo.strides[1], iInfo.strides[0]);
    }
    __syncthreads();

    if (gx < iInfo.dims[0] && gy < iInfo.dims[1]) {
        dim_type i = lx + radius;
        dim_type j = ly + radius;
        dim_type _i = i-1;
        dim_type i_ = i+1;
        dim_type _j = j-1;
        dim_type j_ = j+1;

        float NW = localMem[_i+shrdLen*_j];
        float SW = localMem[i_+shrdLen*_j];
        float NE = localMem[_i+shrdLen*j_];
        float SE = localMem[i_+shrdLen*j_];

        float t1 = localMem[i+shrdLen*_j];
        float t2 = localMem[i+shrdLen*j_];
        dxptr[gy*dxInfo.strides[1]+gx] = (T)(NW+SW - (NE+SE) + 2*(t1-t2));

        t1 = localMem[_i+shrdLen*j];
        t2 = localMem[i_+shrdLen*j];
        dyptr[gy*dyInfo.strides[1]+gx] = (T)(NW+NE - (SW+SE) + 2*(t1-t2));

    }
}


Added comments for spike function.

Added comments for spike function.

git-svn-id: 602a26e73ae9f2a14e2bb95676f2e137fcc39919@3074 7c0444ca-5550-0410-9008-faecdbe78eb5

#include "Retina_params.h"
#include "cl_random.cl"

#ifndef PI
#  define PI 3.1415926535897932
#endif

#ifndef __CL_PLATFORM_H

#  include <math.h>
#  define EXP expf
#  define FMOD fmodf
#  define CL_KERNEL
#  define CL_MEM_GLOBAL
#  define CL_MEM_LOCAL

#else

#  define EXP exp
#  define FMOD __fmodf
#  define CL_KERNEL     __kernel
#  define CL_MEM_GLOBAL __global
#  define CL_MEM_LOCAL  __local

// This stuff needs to be moved to (or obtained from) separate file
// perhaps conversions.h

static inline int kxPos(int k, int nx, int ny, int nf)
{
   return (k/nf) % nx;
}

static inline int kyPos(int k, int nx, int ny, int nf)
{
   return k / (nx*nf);
}

static inline int kIndex(int kx, int ky, int kf, int nx, int ny, int nf)
{
   return kf + (kx + (ky * nx)) * nf;
}

static inline int featureIndex(int k, int nx, int ny, int nf)
{
   return k % nf;
}

static inline int kIndexExtended(int k, int nx, int ny, int nf, int nb)
{
   const int kx_ex = nb + kxPos(k, nx, ny, nf);
   const int ky_ex = nb + kyPos(k, nx, ny, nf);
   const int kf = featureIndex(k, nx, ny, nf);
   return kIndex(kx_ex, ky_ex, kf, nx + 2*nb, ny + 2*nb, nf);
}

#endif /* __CL_PLATFORM_H */

/*
 * Spiking method for Retina
 * Returns 1 if an event should occur, 0 otherwise. This is a stochastic model.
 *
 * REMARKS:
 *      - During ABS_REFACTORY_PERIOD a neuron does not spike
 *      - The neurons that correspond to stimuli (on Image pixels)
 *        spike with probability probStim.
 *      - The neurons that correspond to background image pixels
 *        spike with probability probBase.
 *      - After ABS_REFACTORY_PERIOD the spiking probability
 *        grows exponentially to probBase and probStim respectively.
 *      - The burst of the retina is periodic with period T set by
 *        T = 1000/burstFreq in miliseconds
 *      - When the time t is such that mT < t < mT + burstDuration, where m is
 *        an integer, the burstStatus is set to 1.
 *      - The burstStatus is also determined by the condition that
 *        beginStim < t < endStim. These parameters are set in the input
 *        params file params.stdp
 *      - sinAmp modulates the spiking probability only when burstDuration <= 0
 *        or burstFreq = 0
 *      - probSpike is set to probBase for all neurons.
 *      - for neurons exposed to Image on pixels, probSpike increases with probStim.
 *      - When the probability is negative, the neuron does not spike.
 *
 * NOTES:
 *      - time is measured in milliseconds.
 *
 */
static inline
int spike(float time, float dt,
          float prev, float stimFactor, uint4 rnd_state, const Retina_params * params)
{
   float probSpike;
   float burstStatus = 1;
   float sinAmp = 1.0;

   // input parameters
   //
   float probBase  = params->probBase;
   float probStim  = params->probStim * stimFactor;

   // see if neuron is in a refactory period
   //
   if ((time - prev) < params->abs_refactory_period) {
      return 0;
   }
   else {
      float delta = time - prev - params->abs_refactory_period;
      float refact = 1.0f - EXP(-delta/params->refactory_period);
      refact = (refact < 0) ? 0 : refact;
      probBase *= refact;
      probStim *= refact;
   }

   if (params->burstDuration <= 0 || params->burstFreq == 0) {
      sinAmp = cos( 2*PI*time * params->burstFreq / 1000. );
   }
   else {
      burstStatus = FMOD(time, 1000. / params->burstFreq);
      burstStatus = burstStatus <= params->burstDuration;
   }

   burstStatus *= (int) ( (time >= params->beginStim) && (time < params->endStim) );
   probSpike = probBase;

   if ((int)burstStatus) {
      probSpike += probStim * sinAmp;  // negative prob is OK
   }
   return ( pv_random_prob() < probSpike );
}

//
// update the state of a retinal layer (spiking)
//
//    assume called with 1D kernel
//
CL_KERNEL
void update_state (
    const float time,
    const float dt,
    const Retina_params * params,

    const int nx,
    const int ny,
    const int nf,
    const int nb,

    CL_MEM_GLOBAL uint4 * rnd,
    CL_MEM_GLOBAL float * phiExc,
    CL_MEM_GLOBAL float * phiInh,
    CL_MEM_GLOBAL float * activity,
    CL_MEM_GLOBAL float * prevTime)
{
   int k;
#ifndef PV_USE_OPENCL
for (k = 0; k < nx*ny*nf; k++) {
#else
   k = get_global_id(0);
#endif

   int kex = kIndexExtended(k, nx, ny, nf, nb);

   //
   // kernel (nonheader part) begins here
   //

   // load local variables from global memory
   //
   uint4 l_rnd = rnd[k];
   float l_phiExc = phiExc[k];
   float l_phiInh = phiInh[k];
   float l_prev   = prevTime[kex];
   float l_activ  = activity[kex];

   l_activ = spike(time, dt, l_prev, (l_phiExc - l_phiInh), l_rnd, params);
   l_prev  = (l_activ > 0.0f) ? time : l_prev;

   l_phiExc = 0.0f;
   l_phiInh = 0.0f;

   // store local variables back to global memory
   //
   phiExc[k] = l_phiExc;
   phiInh[k] = l_phiInh;
   prevTime[kex] = l_prev;
   activity[kex] = l_activ;

#ifndef PV_USE_OPENCL
   }
#endif

}

#include "Retina_params.h"
#include "cl_random.cl"

#ifndef PI
#  define PI 3.1415926535897932
#endif

#ifndef __CL_PLATFORM_H

#  include <math.h>
#  define EXP expf
#  define FMOD fmodf
#  define CL_KERNEL
#  define CL_MEM_GLOBAL
#  define CL_MEM_LOCAL

#else

#  define EXP exp
#  define FMOD __fmodf
#  define CL_KERNEL     __kernel
#  define CL_MEM_GLOBAL __global
#  define CL_MEM_LOCAL  __local

// This stuff needs to be moved to (or obtained from) separate file
// perhaps conversions.h

static inline int kxPos(int k, int nx, int ny, int nf)
{
   return (k/nf) % nx;
}

static inline int kyPos(int k, int nx, int ny, int nf)
{
   return k / (nx*nf);
}

static inline int kIndex(int kx, int ky, int kf, int nx, int ny, int nf)
{
   return kf + (kx + (ky * nx)) * nf;
}

static inline int featureIndex(int k, int nx, int ny, int nf)
{
   return k % nf;
}

static inline int kIndexExtended(int k, int nx, int ny, int nf, int nb)
{
   const int kx_ex = nb + kxPos(k, nx, ny, nf);
   const int ky_ex = nb + kyPos(k, nx, ny, nf);
   const int kf = featureIndex(k, nx, ny, nf);
   return kIndex(kx_ex, ky_ex, kf, nx + 2*nb, ny + 2*nb, nf);
}

#endif /* __CL_PLATFORM_H */

static inline
int spike(float time, float dt,
          float prev, float stimFactor, uint4 rnd_state, const Retina_params * params)
{
   float probSpike;
   float burstStatus = 1;
   float sinAmp = 1.0;

   // input parameters
   //
   float probBase  = params->probBase;
   float probStim  = params->probStim * stimFactor;

   // see if neuron is in a refactory period
   //
   if ((time - prev) < params->abs_refactory_period) {
      return 0;
   }
   else {
      float delta = time - prev - params->abs_refactory_period;
      float refact = 1.0f - EXP(-delta/params->refactory_period);
      refact = (refact < 0) ? 0 : refact;
      probBase *= refact;
      probStim *= refact;
   }

   if (params->burstDuration <= 0 || params->burstFreq == 0) {
      sinAmp = cos( 2*PI*time * params->burstFreq / 1000. );
   }
   else {
      burstStatus = FMOD(time, 1000. / params->burstFreq);
      burstStatus = burstStatus <= params->burstDuration;
   }

   burstStatus *= (int) ( (time >= params->beginStim) && (time < params->endStim) );
   probSpike = probBase;

   if ((int)burstStatus) {
      probSpike += probStim * sinAmp;  // negative prob is OK
   }
   return ( pv_random_prob() < probSpike );
}

//
// update the state of a retinal layer (spiking)
//
//    assume called with 1D kernel
//
CL_KERNEL
void update_state (
    const float time,
    const float dt,
    const Retina_params * params,

    const int nx,
    const int ny,
    const int nf,
    const int nb,

    CL_MEM_GLOBAL uint4 * rnd,
    CL_MEM_GLOBAL float * phiExc,
    CL_MEM_GLOBAL float * phiInh,
    CL_MEM_GLOBAL float * activity,
    CL_MEM_GLOBAL float * prevTime)
{
   int k;
#ifndef PV_USE_OPENCL
for (k = 0; k < nx*ny*nf; k++) {
#else
   k = get_global_id(0);
#endif

   int kex = kIndexExtended(k, nx, ny, nf, nb);

   //
   // kernel (nonheader part) begins here
   //

   // params
   //

   float probStim = params->probStim;
   float probBase = params->probBase;

   // load local variables from global memory
   //
   uint4 l_rnd = rnd[k];
   float l_phiExc = phiExc[k];
   float l_phiInh = phiInh[k];
   float l_prev   = prevTime[kex];
   float l_activ  = activity[kex];

   l_activ = spike(time, dt, l_prev, (l_phiExc - l_phiInh), l_rnd, params);
   l_prev  = (l_activ > 0.0f) ? time : l_prev;

   l_phiExc = 0.0f;
   l_phiInh = 0.0f;

   // store local variables back to global memory
   //
   phiExc[k] = l_phiExc;
   phiInh[k] = l_phiInh;
   prevTime[kex] = l_prev;
   activity[kex] = l_activ;

#ifndef PV_USE_OPENCL
   }
#endif

}