removed ald wrw with stride

removed ald wrw with stride

/*
 * 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 DBG_OUT_OF_RNGE 0

// number of filter taps in the processing wk_item
//#define MLO_WEI_WKITEM 5

#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)

// 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
// 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_WEI_SCAN_BLK (MLO_OUT_WEI_EXT_SCAN_BLK)

// max loop over virtual blocks for small images
#define MLO_MAX_WEI_BLK_LOOP_TMP ((MLO_OUT_HORIZ_PIX_SZ + 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)

#define MLO_OUT_HORIZ_PIX_EXT_SZ (MLO_OUT_WEI_EXT_SCAN_BLK * MLO_MAX_WEI_BLK_LOOP)
#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_BATCHS*MLO_N_LCL_OUT_MAPS*MLO_OUT_LCL_SZ)
#if ((MLO_OUT_HEIGHT/MLO_N_ALIGNED_OUT_SCAN_BLK)*MLO_N_ALIGNED_OUT_SCAN_BLK == MLO_OUT_HEIGHT)
#define MLO_BLK_ALIGNED 1
#else
#define MLO_BLK_ALIGNED 0
#endif

// 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)
#if ((MLO_OUT_HORIZ_PIX_SZ-1)*MLO_FILTER_STRIDE0 + MLO_FILTER_SIZE0) > MLO_IN_WIDTH
#define MLO_IN_SCAN_SZ MLO_IN_WIDTH
#else
#define MLO_IN_SCAN_SZ ((MLO_OUT_HORIZ_PIX_SZ-1)*MLO_FILTER_STRIDE0 + MLO_FILTER_SIZE0)
#endif
#define MLO_N_IN_HORIZ_READS ((MLO_IN_SCAN_SZ + MLO_READ_UNIT - 1) / MLO_READ_UNIT)
#define MLO_IN_LCL_WIDTH (MLO_N_IN_HORIZ_READS * MLO_READ_UNIT)
#if MLO_IN_LCL_WIDTH <= MLO_IN_WIDTH
#define MLO_IN_N_PIXS_OFF 0
#else
#define MLO_IN_N_PIXS_OFF (MLO_IN_WIDTH -( MLO_N_IN_HORIZ_READS - 1)*MLO_READ_UNIT)
#endif
#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_BATCHS*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);
static 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
static inline int getWaveId()
{
	int wave_id = 0;

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

	return(wave_id);
}
#endif

static inline int gePhysLocalId()
{
	int lcl_wave_id = get_local_id(0) - ((get_local_id(0) >> MLO_LG2_PHYS_WAVE_SZ) << MLO_LG2_PHYS_WAVE_SZ);
	return(lcl_wave_id);
}

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

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

static 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];
			}

		}
	}
}

static inline void  Kahan_summation(_FLOAT *sum, _FLOAT * c, _FLOAT v)
{
	_FLOAT y = v - *c;    //So far, so good: c is zero.
	_FLOAT t = *sum + y;         //Alas, sum is big, y small, so low-order digits of y are lost.
	*c = (t - *sum) - y;   //(t - sum) recovers the high-order part of y; subtracting y recovers -(low part of y)
	*sum = t;             //Algebraically, c should always be zero. Beware eagerly optimising compilers!
}

static inline void  Kahan_summation_tricked(_FLOAT *sum, _FLOAT * c, _FLOAT v, _FLOAT mod)
{
	_FLOAT y = v - *c;    //So far, so good: c is zero.
	_FLOAT t = *sum + y;         //Alas, sum is big, y small, so low-order digits of y are lost.
	*c = (t - *sum) * mod - y;   //(t - sum) recovers the high-order part of y; subtracting y recovers -(low part of y)
	*sum = t;             //Algebraically, c should always be zero. Beware eagerly optimising compilers!
}

static inline void Kahan_summation2(_FLOAT *sum, _FLOAT *c, _FLOAT *v, int n)
{
	for (int i = 0; i < n; ++i)
	{
		_FLOAT y = v[i] - c[i];    //So far, so good: c is zero.
		_FLOAT t = sum[i] + y;         //Alas, sum is big, y small, so low-order digits of y are lost.
		c[i] = (t - sum[i]) - y;   //(t - sum) recovers the high-order part of y; subtracting y recovers -(low part of y)
		sum[i] = t;             //Algebraically, c should always be zero. Beware eagerly optimising compilers!
	}
}

/*********************************************************************************************************
// wrw algorithm for large filters
// idea:
// split filter taps into sub-tiles along x and y axis with number of tap groups muliples of stride or 1
// for example
// the 5x10 filter has been split into 10 sub-tiles 1x5 each, 1 tap in y direction and 5 taps in x direction.
// those horizontal taps are 0, 2, 4, 6, 8 and 1, 3, 5, 7, 9
// a single vertical tap is 0 or 1 or 2 or 3 or 4.
// one may say sub-tiles are indexed by a vertical tap.
// the partial sum has been calculated into those 10 sub-tiles in parallel.
// the full filter has been calulated by reducing all sub-tiles into a single filter per group.
// teh accumulation has been done over all pixels of several outputs being shared with a single input.
// the accuulation has been done per batch.
//
// the total reduction over all batches has been doesn a separete kerenel.
//
// alg
//
//		until end of output map (MLO_N_OUT_BLK)
//			load input map block in LDS
//			load output maps in LDS
//          for j in output scans
//				for i in output scan interval
//                  accumulate the weights into sub-tiles
//
//		reduce sub-tiles into a single filter for each output
//		write accululated weights
//
// group layout
// 0 - n waves * wave size (n_waves has been defined by host)
// 1 - input channel index
// 2 - output channel/batch index
//
//
// for each batch
//	 accumulate all weights per input/output pair

**********************************************************************************************************/

__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 + reduce buffer

	__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(0); // input map index base

	int o_idx_base = get_group_id(1); // output map index base
	int ib_base = get_group_id(2); // batch index base

	int ib = ib_base*MLO_N_LCL_BATCHS;

	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 gbl_in_off = c_idx * MLO_IN_CHANNEL_STRIDE + ib * MLO_IN_BATCH_STRIDE;
	int gbl_out_off = o_idx * MLO_OUT_CHANNEL_STRIDE + ib * MLO_OUT_BATCH_STRIDE;

	int lcl_id = get_local_id(0);

// weight tile id
	int w_blk_idx = iDiv(lcl_id, MLO_WEI_BLK_SZ);
	int w_idx = iMod(lcl_id, w_blk_idx, MLO_WEI_BLK_SZ);
// weight y
	int w_y = iDiv(w_idx, MLO_WEI_BLK_SZ0);
// weight starting x
	int w_x0 = iMod(w_idx, w_y, MLO_WEI_BLK_SZ0);

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

	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 = lcl_id; i < (MLO_LCL_SZ); i += MLO_GRP_SZ)
	{
		lcl[i] = 0;
	}

	barrier(CLK_LOCAL_MEM_FENCE);

#if 1
	// over all batches

	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 input scans
		__private _FLOAT in_rd_data[MLO_READ_UNIT];

		int gbl_in_scan_off = gbl_in_off;
		int gbl_out_scan_off = gbl_out_off;
		int c_scan = 0;

		for (int p4 = lcl_id;  p4 < MLO_N_IN_HORIZ_READS * (MLO_FILTER_SIZE1 - MLO_FILTER_STRIDE1);
			//				c_scan = iDiv(p4, MLO_N_IN_HORIZ_READS),
			p4 += MLO_GRP_SZ)
		{

			c_scan = iDiv(p4, MLO_N_IN_HORIZ_READS);
			int c_pix4 = iMod(p4, c_scan, MLO_N_IN_HORIZ_READS);
			for (int i = 0; i < MLO_READ_UNIT; ++i)
			{
				in_rd_data[i] = 0;
			}
			if (in_y + c_scan < MLO_IN_HEIGHT)
			{
				int bot_off = gbl_in_scan_off + c_scan * MLO_IN_STRIDE + c_pix4*MLO_READ_UNIT;
#if MLO_IN_N_PIXS_OFF > 0
				if (c_pix4 == MLO_N_IN_HORIZ_READS - 1)
				{
					int i = 0;
					for (; i < MLO_IN_N_PIXS_OFF; ++i)
					{
						in_rd_data[i] = bot[bot_off + i];
#if DBG_OUT_OF_RNGE
						if (bot_off + i >= MLO_IN_BATCH_STRIDE * MLO_BATCH_SZ)
						{
							printf("k:err:in-of-range\n");
						}
#endif

					}

				}
				else
#endif
				{

					for (int i = 0; i < MLO_READ_UNIT; ++i)
					{
						in_rd_data[i] = bot[bot_off + i];
#if DBG_OUT_OF_RNGE
						if (bot_off + i >= MLO_IN_BATCH_STRIDE * MLO_BATCH_SZ)
						{
							printf("k:err:in-of-range\n");
						}
#endif
					}
				}
			}

			int lcl_off = (c_scan + MLO_FILTER_PAD1)*MLO_IN_LCL_WIDTH + MLO_FILTER_PAD0 + c_pix4*MLO_READ_UNIT;

			for (int i = 0; i < MLO_READ_UNIT; ++i)
			{
				lcl_bot[lcl_off + i] = in_rd_data[i];
			}

		}

		in_y += MLO_FILTER_SIZE1 - MLO_FILTER_STRIDE1;

// TO DO: HANDLE PADDING
// over all out blocks
// processing per MLO_N_ALIGNED_OUT_SCAN_BLK output scans

		for (int ob = 0; ob < MLO_N_OUT_BLK; ++ob, in_y += (MLO_IN_LCL_HEIGHT - MLO_FILTER_SIZE1 + MLO_FILTER_STRIDE1), out_y += MLO_N_ALIGNED_OUT_SCAN_BLK)
		{
/// if output height is not multile of MLO_N_ALIGNED_OUT_SCAN_BLK
#if MLO_BLK_ALIGNED == 0
			for (int i = lcl_id; ob == MLO_N_OUT_BLK - 1 && i < MLO_TOTAL_OUT_LCL_SZ; i += MLO_GRP_SZ)
			{
				lcl_top[i] = 0;
			}
#endif

			barrier(CLK_LOCAL_MEM_FENCE);

// fetch input: (MLO_IN_LCL_HEIGHT - MLO_FILTER_SIZE1 + 1)
// TODO:: HANDLE multiple INPUTS
// an overshoot has to be hadled by zero outing output
			gbl_in_scan_off = gbl_in_off + mul24(in_y, MLO_IN_STRIDE);
			int c_scan = 0;
			for (int p4 = lcl_id; p4 < MLO_N_IN_HORIZ_READS * (MLO_IN_LCL_HEIGHT - MLO_FILTER_SIZE1 + MLO_FILTER_STRIDE1)/* && in_y + c_scan < MLO_IN_HEIGHT*/;
				p4 += MLO_GRP_SZ)
			{
				c_scan = iDiv(p4, MLO_N_IN_HORIZ_READS);
				int c_pix4 = iMod(p4, c_scan, MLO_N_IN_HORIZ_READS);
				for(int i = 0; i < MLO_READ_UNIT; ++i)
				{
					in_rd_data[i] = 0;
				}
				if (in_y + c_scan < MLO_IN_HEIGHT)
				{
					int bot_off = gbl_in_scan_off + c_scan * MLO_IN_STRIDE + c_pix4*MLO_READ_UNIT;
#if MLO_IN_N_PIXS_OFF > 0
					if (c_pix4 == MLO_N_IN_HORIZ_READS - 1)
					{
						int i = 0;
						for (; i < MLO_IN_N_PIXS_OFF; ++i)
						{
							in_rd_data[i] = bot[bot_off + i];
#if DBG_OUT_OF_RNGE
							if (bot_off + i >= MLO_IN_BATCH_STRIDE * MLO_BATCH_SZ)
							{
								printf("k:err:in-of-range\n");
							}
#endif
						}
					}
					else
#endif
					{
						for (int i = 0; i < MLO_READ_UNIT; ++i)
						{
							in_rd_data[i] = bot[bot_off + i];
#if DBG_OUT_OF_RNGE
							if (bot_off + i >= MLO_IN_BATCH_STRIDE * MLO_BATCH_SZ)
							{
								printf("k:err:in-of-range\n");
							}
#endif

						}
					}

				}

				int lcl_off = (c_scan + MLO_FILTER_SIZE1 - MLO_FILTER_STRIDE1)*MLO_IN_LCL_WIDTH + MLO_FILTER_PAD0 + c_pix4*MLO_READ_UNIT;

				for (int i = 0; i < MLO_READ_UNIT; ++i)
				{
					lcl_bot[lcl_off + i] = in_rd_data[i];
				}

			}

			gbl_out_scan_off = gbl_out_off + mul24(out_y, MLO_OUT_STRIDE);

// over all outputs groups
// MLO_N_OUT_BLK_GRP outputs reuse the same input
// each output blk is MLO_N_LCL_OUT_MAPS outputs
// MLO_N_LCL_OUT_MAPS nuber is restricted by LDS size

			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)
			{

// fetch output. MLO_N_ALIGNED_OUT_SCAN_BLK output scans, each of size MLO_N_OUT_HORIZ_READS

				__private _FLOAT out_rd_data[MLO_READ_UNIT];

				for (int oo_p4 = lcl_id; oo_p4 < (MLO_N_LCL_OUT_MAPS*MLO_N_ALIGNED_OUT_SCAN_BLK*MLO_N_OUT_HORIZ_READS);
					oo_p4 += MLO_GRP_SZ)
				{
					int o = iDiv(oo_p4, (MLO_N_ALIGNED_OUT_SCAN_BLK*MLO_N_OUT_HORIZ_READS));
					int o_pX4 = iMod(oo_p4, o, (MLO_N_ALIGNED_OUT_SCAN_BLK*MLO_N_OUT_HORIZ_READS));
					int o_scan = iDiv(o_pX4, MLO_N_OUT_HORIZ_READS);
					int o_pix4 = iMod(o_pX4, o_scan, MLO_N_OUT_HORIZ_READS);
					for (int i = 0; i < MLO_READ_UNIT; ++i)
					{
						out_rd_data[i] = 0;
					}

					if (out_y + o_scan < MLO_OUT_HEIGHT
						&& o_idx + og *MLO_N_LCL_OUT_MAPS + o < MLO_N_OUTPUTS
						)
					{
						// scan has been fetch by 4
						// here the non-multiple of 4 scan has been handled
						// also makes sure the input garbage hs been multipled by 0
						int top_off = gbl_out_scan_off1 + o*MLO_OUT_CHANNEL_STRIDE + o_scan * MLO_OUT_STRIDE + o_pix4*MLO_READ_UNIT;
#if MLO_OUT_N_PIXS_OFF > 0
						if (o_pix4 == (MLO_N_OUT_HORIZ_READS - 1))
						{
							int i = 0;
							for (; i < MLO_OUT_N_PIXS_OFF; ++i)
							{
								out_rd_data[i] = top_df[top_off + i];
#if DBG_OUT_OF_RNGE
								if (top_off + i >= MLO_OUT_BATCH_STRIDE * MLO_BATCH_SZ)
								{
									printf("k:err:out-of-range\n");
								}
#endif

							}

						}
						else
#endif
						{
							for (int i = 0; i < MLO_READ_UNIT; ++i)
							{
								out_rd_data[i] = top_df[top_off + i];
#if DBG_OUT_OF_RNGE
								if (top_off + i >= MLO_OUT_BATCH_STRIDE * MLO_BATCH_SZ)
								{
									printf("k:err:out-of-range\n");
								}
#endif
							}
						}

					} // if (out_y + o_scan < MLO_OUT_HEIGHT && o_idx + og *MLO_N_LCL_OUT_MAPS + o < MLO_N_OUTPUTS)

					int lcl_off = (o)* MLO_OUT_LCL_SZ + o_scan * MLO_OUT_HORIZ_PIX_EXT_SZ + o_pix4*MLO_READ_UNIT;
					for (int i = 0; i < MLO_READ_UNIT; ++i)
					{
						lcl_top[lcl_off + i] = out_rd_data[i];
					}

				} //	for (int oo_p4 = lcl_id; oo_p4 < (MLO_N_LCL_OUT_MAPS*MLO_N_ALIGNED_OUT_SCAN_BLK*MLO_N_OUT_HORIZ_READS); oo_p4 += MLO_GRP_SZ)

				barrier(CLK_LOCAL_MEM_FENCE);

// process
// algorithm

#if 1
				//				if (w_blk_idx < MLO_MAX_WEI_BLK_LOOP)
				{
// over all input scans in LDS
					for (int j = 0; j < MLO_N_ALIGNED_OUT_SCAN_BLK; ++j)
					{

// prefetch proper inputs pixels.
// they are MLO_WEI_BLK_SZ0 apart taps of the filter

						_FLOAT i_vals[MLO_WEI_WKITEM];

						for (int w = 0; w < (MLO_WEI_WKITEM - (MLO_FILTER_STRIDE0 / MLO_WEI_BLK_SZ0)); ++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)
						{

// read the current input pixel
							for (int w = (MLO_WEI_WKITEM - (MLO_FILTER_STRIDE0 / MLO_WEI_BLK_SZ0)); w < MLO_WEI_WKITEM; ++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 + i) * MLO_FILTER_STRIDE0 + w_x;
								_FLOAT i_val = lcl_bot[i_off];

								i_vals[w] = i_val;
							}

// for each output accumulate a proper filter tap
							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 (i_val * o_val != 0 && ib == 0 && c_idx == 0 && o_idx + og*MLO_N_LCL_OUT_MAPS + o == 0 && w_y == 0 && w_x == 1 && w_blk_idx < MLO_MAX_WEI_BLK_LOOP)
									{
										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;
										printf("K:s:%d %d %d %d %d %d %d %d %d %d   %f %f %f %f\n",
											MLO_OUT_WEI_SCAN_BLK,
											lcl_id,
											b,
											ob,
											w_blk_idx,
											j,
											i,
											w,
											i_off,
											(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,
											i_val,
											o_val
										);
									}
#endif

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

							} // for (int o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)

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

							}
						} // for (int i = 0; i < MLO_OUT_WEI_SCAN_BLK; ++i)
					} // for (int j = 0; j < MLO_N_ALIGNED_OUT_SCAN_BLK; ++j)
				}
#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 the input data tail inside LDS to reduce mem bandwidth
			c_scan = 0;
			for (int p4 = lcl_id; p4 < MLO_N_IN_HORIZ_READS * (MLO_FILTER_SIZE1 - MLO_FILTER_STRIDE1);
				p4 += MLO_GRP_SZ, c_scan = iDiv(p4, MLO_N_IN_HORIZ_READS))
			{
				int c_pix4 = iMod(p4, c_scan, MLO_N_IN_HORIZ_READS);

				*(MLO_READ_TYPE*)in_rd_data = *(__local MLO_READ_TYPE*)&lcl_bot[(c_scan + (MLO_IN_LCL_HEIGHT - MLO_FILTER_SIZE1 + MLO_FILTER_STRIDE1))*(MLO_IN_LCL_WIDTH)+MLO_FILTER_PAD0 + c_pix4*MLO_READ_UNIT];
				*(__local 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;

	barrier(CLK_LOCAL_MEM_FENCE);

#endif

// send it out
	  // inputs are outputs
	int wei_df_off = ((ib * MLO_N_OUTPUTS + 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[wei_lcl_off] = pvt_accum[(og * MLO_N_LCL_OUT_MAPS + o) * MLO_WEI_WKITEM + w];

			}

		}

		barrier(CLK_LOCAL_MEM_FENCE);

		// read into real filter table

		for(int l = lcl_id; l < (MLO_N_LCL_OUT_MAPS *MLO_WEI_CHANNEL_STRIDE); l+=MLO_GRP_SZ)
		{
			int oo = iDiv(l, MLO_WEI_CHANNEL_STRIDE);
			int wei_i = iMod(l, oo, MLO_WEI_CHANNEL_STRIDE);
			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
			// inputs are outputs
			int wei_df_off = ((ib * MLO_N_OUTPUTS + o_idx) * (int)MLO_WEI_BATCH_STRIDE)
				// this input channel
				+ mul24(c_idx, (int)MLO_WEI_CHANNEL_STRIDE);

			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 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 1
			if (o_idx + (og *  MLO_N_LCL_OUT_MAPS + oo) == 0 && c_idx == 3 && wei_i == 0)
			{
				printf("K:o: %d %f\n",
					ib,
					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

		}

		barrier(CLK_LOCAL_MEM_FENCE);

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

}

// final reduction kernel
// add filters over batches
__attribute__((reqd_work_group_size(MLO_UT_GRP_SZ0, 1, 1)))
__kernel void MLOpenCvBwdWrW_rdc(
	const __global _FLOAT * weight_df_tmp,
	__global _FLOAT * weights_df
)
{
	int gbl_id = get_global_id(0);
	int wei_idx0 = gbl_id * MLO_UT_READ_UNIT;

	int wei_blk_idx = iDiv(wei_idx0, MLO_WEI_CHANNEL_STRIDE);
	int wei_idx = iMod(wei_idx0, wei_blk_idx, MLO_WEI_CHANNEL_STRIDE);

	_FLOAT pvt_accum_wei[MLO_UT_READ_UNIT];
	for (int i = 0; i < MLO_UT_READ_UNIT; ++i)
	{
		pvt_accum_wei[i] = 0;
	}

	int batch_loop = (MLO_BATCH_SZ + (MLO_N_BATCH_LOOPS*MLO_N_LCL_BATCHS) - 1) / (MLO_N_BATCH_LOOPS*MLO_N_LCL_BATCHS);
	for (int i = 0; i < batch_loop; ++i)
	{
		*(MLO_UT_READ_TYPE*)pvt_accum_wei
			+= *(__global MLO_UT_READ_TYPE*)&weight_df_tmp[(wei_blk_idx * MLO_WEI_CHANNEL_STRIDE + i* MLO_N_OUTPUTS*MLO_WEI_BATCH_STRIDE)  + wei_idx];
	}

	*(__global MLO_UT_READ_TYPE*)&weights_df[wei_idx0] = *(MLO_UT_READ_TYPE*)pvt_accum_wei;

}


r2039: Debian build

r2039: Debian build

;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
;;;; *************************************************************************
;;;; FILE IDENTIFICATION
;;;;
;;;; Name:          clsql-uffi-loader.sql
;;;; Purpose:       library loader using CLSQL UFFI helper library
;;;; Programmers:   Kevin M. Rosenberg
;;;; Date Started:  Mar 2002
;;;;
;;;; $Id: clsql-uffi-loader.cl,v 1.6 2002/05/14 16:05:43 kevin Exp $
;;;;
;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg
;;;;
;;;; CLSQL users are granted the rights to distribute and use this software
;;;; as governed by the terms of the Lisp Lesser GNU Public License
;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
;;;; *************************************************************************

(declaim (optimize (debug 3) (speed 3) (safety 1) (compilation-speed 0)))
(in-package :clsql-uffi)

(defvar *clsql-uffi-library-filename*
  (uffi:find-foreign-library
   :names "clsql-uffi"
   :directories
   `(,(translate-logical-pathname
       "CL-LIBRARY:clsql;interfaces;clsql-uffi;clsql-uffi.so")
     "/usr/share/common-lisp/source/clsql/interfaces/clsql-uffi/")))

(defvar *clsql-uffi-supporting-libraries* '("c")
  "Used only by CMU. List of library flags needed to be passed to ld to
load the MySQL client library succesfully.  If this differs at your site,
set to the right path before compiling or loading the system.")

(defvar *uffi-library-loaded* nil
  "T if foreign library was able to be loaded successfully")

(defun load-uffi-foreign-library ()
  (if (uffi:load-foreign-library *clsql-uffi-library-filename*
				 :module "clsql-uffi"
				 :supporting-libraries
				 *clsql-uffi-supporting-libraries*)
      (setq *uffi-library-loaded* t)
    (warn "Unable to load helper library ~A (~S)" *clsql-uffi-library-filename*
	  (logical-pathname-translations "CL-LIBRARY"))))

(load-uffi-foreign-library)

;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
;;;; *************************************************************************
;;;; FILE IDENTIFICATION
;;;;
;;;; Name:          clsql-uffi-loader.sql
;;;; Purpose:       library loader using CLSQL UFFI helper library
;;;; Programmers:   Kevin M. Rosenberg
;;;; Date Started:  Mar 2002
;;;;
;;;; $Id: clsql-uffi-loader.cl,v 1.5 2002/05/14 16:03:52 kevin Exp $
;;;;
;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg
;;;;
;;;; CLSQL users are granted the rights to distribute and use this software
;;;; as governed by the terms of the Lisp Lesser GNU Public License
;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
;;;; *************************************************************************

(declaim (optimize (debug 3) (speed 3) (safety 1) (compilation-speed 0)))
(in-package :clsql-uffi)

(defvar *clsql-uffi-library-filename*
  (uffi:find-foreign-library
   :names "clsql-uffi"
   :directories
   (translate-logical-pathname
    "CL-LIBRARY:clsql;interfaces;clsql-uffi;clsql-uffi.so")
   "/usr/share/common-lisp/source/clsql/interfaces/clsql-uffi/"))

(defvar *clsql-uffi-supporting-libraries* '("c")
  "Used only by CMU. List of library flags needed to be passed to ld to
load the MySQL client library succesfully.  If this differs at your site,
set to the right path before compiling or loading the system.")

(defvar *uffi-library-loaded* nil
  "T if foreign library was able to be loaded successfully")

(defun load-uffi-foreign-library ()
  (if (uffi:load-foreign-library *clsql-uffi-library-filename*
				 :module "clsql-uffi"
				 :supporting-libraries
				 *clsql-uffi-supporting-libraries*)
      (setq *uffi-library-loaded* t)
    (warn "Unable to load helper library ~A (~S)" *clsql-uffi-library-filename*
	  (logical-pathname-translations "CL-LIBRARY"))))

(load-uffi-foreign-library)


write_image.cl: fix to pass conformance test

/* OpenCL built-in library: write_image()

   Copyright (c) 2013 Ville Korhonen

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   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 Software.

   THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
*/

#include "templates.h"
#include "pocl_image_rw_utils.h"

static const int ARGB_MAP[] = { 3, 0, 1, 2 };
static const int BGRA_MAP[] = { 2, 1, 0, 3 };

static int map_channel(int i, int order) {
  switch(order)
    {
      case CL_ARGB: return ARGB_MAP[i];
      case CL_BGRA: return BGRA_MAP[i];
      case CL_RGBA:
      default: return i;
    }
  return i;
}

/* writes pixel to coord in image */
static void pocl_write_pixel (void* color_, global dev_image_t* dev_image,
                       int4 coord)
{
  uint4 *color = (uint4*)color_;
  int width = dev_image->_width;
  int height = dev_image->_height;
  int num_channels = dev_image->_num_channels;
  int order = dev_image->_order;
  int elem_size = dev_image->_elem_size;
  int const base_index =
    (coord.x + coord.y*width + coord.z*height*width) * num_channels;

  if (order == CL_A)
    {
      if (elem_size == 1)
        ((uchar*) (dev_image->_data))[base_index] = (*color)[3];
      else if (elem_size == 2)
        ((ushort*) (dev_image->_data))[base_index] = (*color)[3];
      else if (elem_size == 4)
        ((uint*) (dev_image->_data))[base_index] = (*color)[3];
      return;
    }

  if (elem_size == 1)
    {
      for (int i=0; i<num_channels; i++)
        {
          ((uchar*) (dev_image->_data))[base_index + i] = (*color)[map_channel(i, order)];
        }
    }
  else if (elem_size == 2)
    {
      for (int i=0; i<num_channels; i++)
        {
          ((ushort*) dev_image->_data)[base_index + i] = (*color)[map_channel(i, order)];
        }
    }
  else if (elem_size == 4)
    {
      for (int i=0; i<num_channels; i++)
        {
          ((uint*) dev_image->_data)[base_index + i] = (*color)[map_channel(i, order)];
        }
    }
}

static constant float4 maxval8 = (float4)UCHAR_MAX;
static constant float4 maxval16 = (float4)USHRT_MAX;
static constant float4 maxval8_2 = (float4)((float)UCHAR_MAX / 2.0f);
static constant float4 maxval16_2 = (float4)((float)USHRT_MAX / 2.0f);
static constant float4 minval8 = ((float4)(SCHAR_MIN));
static constant float4 minval16 = ((float4)(SHRT_MIN));

// only for CL_SNORM_INT8, CL_UNORM_INT8, CL_SNORM_INT16, CL_UNORM_INT16,
static uint4 convert_float4_to_uint4(float4 color, int type, int elem_size)
{
  if ((type == CL_SNORM_INT8) ||
      (type == CL_SNORM_INT16))
    {
      // <-1.0, 1.0> to <I*_MIN, I*_MAX>
      // -1.0,1.0 -> 0.0,2.0 -> * Umax/2.0 -> + Smin
      if (elem_size == 1)
        return convert_uint4((color + (float4)1.0f) * maxval8_2 + minval8);
      else
        return convert_uint4((color + (float4)1.0f) * maxval16_2 + minval16);
    }
  else
    {
      if (elem_size == 1)
        return convert_uint4(maxval8 * color);
      else
        return convert_uint4(maxval16 * color);
    }
}

/*
write_imagei can only be used with image objects created with image_channel_data_type
set to one of the following values: CL_SIGNED_INT8, CL_SIGNED_INT16, and CL_SIGNED_INT32.

write_imageui functions can only be used with image objects created with image_channel_data_type
set to one of the following values: CL_UNSIGNED_INT8, CL_UNSIGNED_INT16, or CL_UNSIGNED_INT32.
*/

#define IMPLEMENT_WRITE_IMAGE_INT_COORD(__IMGTYPE__,__POSTFIX__,        \
                                        __COORD__,__DTYPE__)            \
  void _CL_OVERLOADABLE write_image##__POSTFIX__(__IMGTYPE__ image,     \
                                                  __COORD__ coord,      \
                                                  __DTYPE__ color)      \
  {                                                                     \
    int4 coord4;                                                        \
    INITCOORD##__COORD__(coord4, coord);                                \
    global dev_image_t* i_ptr = __builtin_astype (image, global dev_image_t*); \
    uint4 color2 = as_uint4(color);                                     \
    pocl_write_pixel (&color2, i_ptr, coord4);                          \
  }                                                                     \

/*
write_imagef can only be used with image objects created with image_channel_data_type set to one of the pre-defined packed formats
 or set to CL_SNORM_INT8, CL_UNORM_INT8, CL_SNORM_INT16, CL_UNORM_INT16, CL_HALF_FLOAT or CL_FLOAT.
*/

#define IMPLEMENT_WRITE_IMAGE_INT_COORD_FLOAT4(__IMGTYPE__,             \
                                               __COORD__)               \
  void _CL_OVERLOADABLE write_imagef             (__IMGTYPE__ image,    \
                                                  __COORD__ coord,      \
                                                 float4 color)          \
  {                                                                     \
    int4 coord4;                                                        \
    INITCOORD##__COORD__(coord4, coord);                                \
    global dev_image_t* i_ptr = __builtin_astype (image, global dev_image_t*); \
    if (i_ptr->_data_type == CL_FLOAT)                                  \
      pocl_write_pixel (&color, i_ptr, coord4);                         \
    else                                                                \
    {                                                                   \
      uint4 color2 = convert_float4_to_uint4(color,                     \
                                             i_ptr->_data_type,         \
                                             i_ptr->_elem_size);        \
      pocl_write_pixel (&color2, i_ptr, coord4);                        \
    }                                                                   \
  }                                                                     \

IMPLEMENT_WRITE_IMAGE_INT_COORD ( IMG_WO_AQ image2d_t, ui, int2, uint4)
IMPLEMENT_WRITE_IMAGE_INT_COORD ( IMG_WO_AQ image2d_t, ui, int4, uint4)

IMPLEMENT_WRITE_IMAGE_INT_COORD ( IMG_WO_AQ image2d_t, i, int2, int4)
IMPLEMENT_WRITE_IMAGE_INT_COORD ( IMG_WO_AQ image2d_t, i, int4, int4)

IMPLEMENT_WRITE_IMAGE_INT_COORD_FLOAT4 ( IMG_WO_AQ image2d_t, int2)
IMPLEMENT_WRITE_IMAGE_INT_COORD_FLOAT4 ( IMG_WO_AQ image3d_t, int4)

#if CLANG_HAS_IMAGE_AS

IMPLEMENT_WRITE_IMAGE_INT_COORD ( IMG_RW_AQ image2d_t, ui, int2, uint4)
IMPLEMENT_WRITE_IMAGE_INT_COORD ( IMG_RW_AQ image2d_t, ui, int4, uint4)

IMPLEMENT_WRITE_IMAGE_INT_COORD ( IMG_RW_AQ image2d_t, i, int2, int4)
IMPLEMENT_WRITE_IMAGE_INT_COORD ( IMG_RW_AQ image2d_t, i, int4, int4)

IMPLEMENT_WRITE_IMAGE_INT_COORD_FLOAT4 ( IMG_RW_AQ image2d_t, int2)
IMPLEMENT_WRITE_IMAGE_INT_COORD_FLOAT4 ( IMG_RW_AQ image3d_t, int4)

#endif

/* OpenCL built-in library: write_image()

   Copyright (c) 2013 Ville Korhonen

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   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 Software.

   THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
*/

#include "templates.h"
#include "pocl_image_rw_utils.h"

#if (__clang_major__ > 3) || ((__clang_major__ == 3) && (__clang_minor__ >= 5))
// Clang 3.5 crashes in case trying to cast to the private pointer,
// adding the global qualifier fixes it. Clang 3.4 crashes if it's
// there. The issue is in SROA.
#define ADDRESS_SPACE global
#else
#define ADDRESS_SPACE
#endif

// 3.9 needs access qualifier
// TODO: rw images
#ifdef CLANG_OLDER_THAN_3_9
#define IMG_WRITE_AQ
#else
#define IMG_WRITE_AQ __write_only
#endif

/* writes pixel to coord in image */
void pocl_write_pixel (void* color_, ADDRESS_SPACE dev_image_t* dev_image,
                       int4 coord)
{
  uint4 *color = (uint4*)color_;
  int width = dev_image->_width;
  int height = dev_image->_height;
  int num_channels = dev_image->_num_channels;
  int i = num_channels;
  int elem_size = dev_image->_elem_size;
  int const base_index =
    (coord.x + coord.y*width + coord.z*height*width) * num_channels;

  if (dev_image->_order == CL_A)
    {
      if (elem_size == 1)
        ((uchar*) (dev_image->_data))[base_index] = (*color)[3];
      else if (elem_size == 2)
        ((ushort*) (dev_image->_data))[base_index] = (*color)[3];
      else if (elem_size == 4)
        ((uint*) (dev_image->_data))[base_index] = (*color)[3];
      return;
    }

  if (elem_size == 1)
    {
      while (i--)
        {
          ((uchar*) (dev_image->_data))[base_index + i] = (*color)[i];
        }
    }
  else if (elem_size == 2)
    {
      while (i--)
        {
          ((ushort*) dev_image->_data)[base_index + i] = (*color)[i];
        }
    }
  else if (elem_size == 4)
    {
      while (i--)
        {
          ((uint*) dev_image->_data)[base_index + i] = (*color)[i];
        }
    }
}

/* Implementation for write_image with any image data type and int coordinates
   __IMGTYPE__ = image type (image2d_t, ...)
   __DTYPE__  = data type to be read (int4 or uint4 float4)
   __POSTFIX__ = function name postfix (i, ui, f)
   __COORD__   = coordinate type (int, int2, int4)
*/
#define IMPLEMENT_WRITE_IMAGE_INT_COORD(__IMGTYPE__,__DTYPE__,__POSTFIX__, \
                                        __COORD__)                      \
  void _CL_OVERLOADABLE write_image##__POSTFIX__ (__write_only __IMGTYPE__ image,    \
                                                  __COORD__ coord,      \
                                                  __DTYPE__ color)      \
  {                                                                     \
    int4 coord4;                                                        \
    INITCOORD##__COORD__(coord4, coord);                                \
    global dev_image_t* i_ptr = __builtin_astype (image, global dev_image_t*); \
    pocl_write_pixel (&color, i_ptr, coord4);                             \
  }                                                                     \

IMPLEMENT_WRITE_IMAGE_INT_COORD (image2d_t, uint4, ui, int2)
IMPLEMENT_WRITE_IMAGE_INT_COORD (image2d_t, float4, f, int2)
IMPLEMENT_WRITE_IMAGE_INT_COORD (image3d_t, float4, f, int4)


Properly parsing vcxproj files to be relative

(use-package :regexp)

(load "cl-fad/load.lisp" :verbose nil)

(defstruct rdata start-marker end-marker replacement-callback include-markers)

(setq project-file-extension "vcxproj")

(defun regexp-replace (string pat repl)
  (reduce #'(lambda (x y) (string-concat x repl y))
          (regexp:regexp-split pat string))
)

(defun file-string (path)
  (with-open-file (infile path :if-does-not-exist nil)
    (cond ((not (null infile))
            (format nil "~{~A~^~%~}"
              (loop
                for line = (read-line infile nil)
                while line
                collect line
              )
            )
          )
          (t nil) ; file not found
    )
  )
)

(defun write-file (file-name content)
  (with-open-file (outfile file-name
      :direction :output
      :if-exists :supersede
      :if-does-not-exist :create)
  (format outfile content)))

(defmacro get-next-substr-index (str &key start-marker end-marker start-index end-index include-markers (next-index 0))
  `(progn
    (let ((start-m (match ,start-marker ,str :start ,next-index))
         )
      (cond ((null start-m) nil)
            (t
              (setq ,start-index  (if include-markers
                                     (match-start start-m)
                                     (match-end start-m)
                                  )
              )
              (let ((end-m (match ,end-marker ,str :start (match-end start-m))))
                (cond ((null end-m) nil)
                      (t
                        (setq ,end-index  (if include-markers
                                             (match-end end-m)
                                             (match-start end-m)
                                          )
                        )
                        (match-end end-m)
                      )
                )
              )
            )
      )
    )
  )
)
(defun concat-string-list (s)
  (format nil "~{~A~}" s))

(defun parse-replace (str template)
    (concat-string-list
      (let ((sm (rdata-start-marker template))
            (em (rdata-end-marker template))
            (callback (rdata-replacement-callback template))
            (include-markers (rdata-include-markers template))
            )
           (write-line (format nil "Replacing: ~A to ~A" sm em))
           (loop  with index = 0
                  do (setq next-index (get-next-substr-index str :start-marker sm
                               :end-marker em
                               :start-index si
                               :end-index ei
                               :next-index index
                               :include-markers include-markers))
                  if (null next-index)
                    collect (progn (write-line (format nil "~A -> ~A" index (length str)))
                              (subseq str index)
                             )
                  while next-index
                  ;collect (subseq str index next-index)
                  collect (subseq str index si)
                  collect (funcall callback (subseq str si ei))
                  collect (subseq str ei next-index)
                  do (progn (write-line (format nil "~A -> [~A ~A] -> ~A" index si ei next-index))
                        (setq index next-index)
                      )
           )
      )
    )
)

(defun apply-replacement-templates (str templates)
  (cond ((null templates) str)
        (t (apply-replacement-templates
            (parse-replace str (car templates))
            (cdr templates)
           )
        )
  )
)

(defun apply-parse-file (file-name-in file-name-out templates)
  (write-file file-name-out
    (apply-replacement-templates (file-string file-name-in) templates)
  )
)

(defun replace-all (string part replacement &key (test #'char=))
  "Returns a new string in which all the occurences of the part
is replaced with replacement."
  (with-output-to-string (out)
    (loop with part-length = (length part)
       for old-pos = 0 then (+ pos part-length)
       for pos = (search part string
                         :start2 old-pos
                         :test test)
       do (write-string string out
                        :start old-pos
                        :end (or pos (length string)))
       when pos do (write-string replacement out)
       while pos)))

(setq rdata-list nil)
(defun add-rdata (&rest args)
  (let ((rd (apply #'make-rdata args)))
    (setq rdata-list (cons rd rdata-list))
  )
)
(defun get-macro (key) (gethash key macro-hash))

(setq tp1 (make-rdata :start-marker "<data[^>]*>"
                     :end-marker "</data>"
                     :replacement-callback (lambda (str) "_123_")
                     :include-markers T))
(setq build-dir "C:[\\/]projects[\\/]orbbec[\\/]SenseKitSDK-0.1.0-win32[\\/]samples[\\/]build")
(setq lambda-path-to-sln-dir (lambda (str) (regexp-replace str build-dir "$(SolutionDir)")))
(setq lambda-remove (lambda (str) ""))

(add-rdata :start-marker "<AdditionalIncludeDirectories>"
           :end-marker "</AdditionalIncludeDirectories>"
           :replacement-callback (lambda (str) (replace-all str "\\$$(SolutionDir)" "$(SolutionDir)")))
(add-rdata :start-marker "<OutDir[^>]*>"
           :end-marker "</OutDir>"
           :replacement-callback lambda-path-to-sln-dir)
(add-rdata :start-marker "<ImportLibrary[^>]*>"
           :end-marker "</ImportLibrary>"
           :replacement-callback lambda-path-to-sln-dir)
(add-rdata :start-marker "<ProgramDataBaseFile[^>]*>"
           :end-marker "</ProgramDataBaseFile>"
           :replacement-callback lambda-path-to-sln-dir)
(add-rdata :start-marker "[^<>]*<ItemGroup[^>]*>[^<]*<CustomBuild[^>]*CMakeLists[.]txt[^>]*>"
           :end-marker "</CustomBuild>[^<]*</ItemGroup>"
           :replacement-callback lambda-remove
           :include-markers T)
(add-rdata :start-marker "[^<>]*<ItemGroup[^>]*>[^<]*<ProjectReference[^>]*ZERO_CHECK[.]vcxproj[^>]*>"
           :end-marker "</ProjectReference>[^<]*</ItemGroup>"
           :replacement-callback lambda-remove
           :include-markers T)

(setq f1 "abc <data>123</data> fdsa <data-type>9090</data> lala")
(setq fni "DepthReader.vcxproj")
(setq fno "DepthReader.vcxproj.out")

(defun mapc-directory-tree (fn directory)
  (dolist (entry (cl-fad:list-directory directory))
    (when (cl-fad:directory-pathname-p entry)
      (mapc-directory-tree fn entry))
    (funcall fn entry)))

(defun get-temp-filename (fn)
  (format nil "~A.tmp" fn))

(defun process-file (filename-in)
  (let ((filename-out (get-temp-filename filename-in)))
    (apply-parse-file filename-in filename-out rdata-list)
    (delete-file filename-in)
    (rename-file filename-out filename-in)
  )
)

(defun process (dir)
  (let ((target-directory (if (null dir)
                              (ext:cd)
                              dir)))
    (write-line (format nil "Base directory: ~A~%" target-directory))
    (mapc-directory-tree (lambda (x)
                           (when (equal (pathname-type x) project-file-extension)
                             (write-line (format nil "~A"
                                                 (enough-namestring x target-directory)
                                                 ))
                             (process-file (namestring x))))
                         target-directory)))

(defun _ () (load "parse-replace.cl" :verbose nil))

(defun t1 ()
  (write-line (parse-replace f1 tp1))
)
(defun t2 ()
  (apply-parse-file fni fno rdata-list)
)

(when (>= (length *args*) 2)
  (setq path (car *args*))
  (setq template-file (cdr *args*))
  (parse-replace (file-string path) template-file)
)

(process "files")

(defun file-string (path)
  (with-open-file (infile path :if-does-not-exist nil)
    (cond ((not (null infile))
            (format nil "~{~A~^~%~}"
              (loop
                for line = (read-line infile nil)
                while line
                collect line
              )
            )
          )
          (t nil) ; file not found
    )
  )
)

(defun write-file (file-name content)
    (with-open-file (outfile file-name
        :direction :output
        :if-exists :overwrite
        :if-does-not-exist :create)
    (format outfile content)))

(defmacro get-next-substr-index (str &key start-marker end-marker start-index end-index (next-index 0))
  `(progn
    (let ((start-marker-index (search ,start-marker ,str :start2 ,next-index))
         )
      (cond ((null start-marker-index) nil)
            (t
              (setq ,start-index (+ start-marker-index (length ,start-marker)))
              (setq ,end-index (search ,end-marker ,str :start2 ,start-index))
              (cond ((null ,end-index) nil)
                    (t
                      (+ ,end-index (length ,end-marker))
                    )
              )
            )
      )
    )
  )
)
(defun concat-string-list (s)
  (format nil "~{~A~}" s))

(defstruct rdata start-marker end-marker replacement)

(defun parse-replace (str template)
    (concat-string-list
      (let ((sm (rdata-start-marker template))
            (em (rdata-end-marker template))
            (replacement (rdata-replacement template))
            )
           (loop  with index = 0
                  do (setq next-index (get-next-substr-index str :start-marker sm
                               :end-marker em
                               :start-index si
                               :end-index ei
                               :next-index index))
                  if (null next-index)
                    collect (progn (write-line (format nil "~A -> ~A" index (length str)))
                              (subseq str index)
                             )
                  while next-index
                  ;collect (subseq str index next-index)
                  collect (subseq str index si)
                  collect replacement
                  collect (subseq str ei next-index)
                  do (progn (write-line (format nil "~A -> [~A ~A] -> ~A" index si ei next-index))
                        (setq index next-index)
                      )
           )
      )
    )
)

(defun apply-parse-file (file-name-in file-name-out template)
  (write-file file-name-out (parse-replace (file-string file-name-in) template))
)

(setq tp1 (make-rdata :start-marker "["
                     :end-marker "]"
                     :replacement "_123_"))

(setq tp2 (make-rdata :start-marker "<AdditionalIncludeDirectories>"
                     :end-marker "</AdditionalIncludeDirectories>"
                     :replacement "_123_"))

(setq f1 "abc [123] fdsa [9090] lala")
(setq fni "DepthReader.vcxproj")
(setq fno "DepthReader.vcxproj.out")

(defun _ () (load "parse-replace.cl" :verbose nil))

(defun t1 ()
  (write-line (parse-replace f1 tp1))
)
(defun t2 ()
  (apply-parse-file fni fno tp2)
)
(when (>= (length *args*) 2)
  (setq path (car *args*))
  (setq template (cdr *args*))
  (parse-replace (file-string path) template)
)

(t2)