Added myls.cl

Added myls.cl

(headers
	stdio
	stdlib
	"string"
	pwd
	grp
	dirent
	time
	sys/types
	sys/stat)

(syn true "True")
(syn false "False")
(define True 1)
(define False 0)

(define (macro !execinfop !x)
	(.and !x (.or !s-ixusr !s-ixgrp !s-ixoth)))
(define (macro !chifelse !p !a !b)
	(@putchar (? !p (paren !a) !b)))
(define (macro !buffer !x)
	(? !x True False))
(define (macro !nop !x) !x)

(typedef (struct dirent) dirent)

(template incptr (x) (set x (addr (nth x 1))))
(func (pt parse-arg) char (

	((pt argv 2) char)
	((pt search 2) char)
	(argp char)
	((pt slot) int))

	(var i int 0)
	(while (ptr argv)
		(var (pt start 2) char search)
		(while (ptr start)
			(if (not (@strcmp (pt argv) (pt start)))
				(progn
					(if argp
						(return (nth argv 1)))
					(if (lt (pt slot) i)
						(set (pt slot) i))
					(return (str !true))))
			(incptr start))
		(incptr argv)
		(pinc i))
	(return !null))

(const (arr (pt !classify) nil)       char (arr-decl (str "-c") (str "-classify")        !null))
(const (arr (pt !diskusage) nil)      char (arr-decl (str "-d") (str "-disk-usage")      !null))
(const (arr (pt !longlisting) nil)    char (arr-decl (str "-l") (str "-long-listing")    !null))
(const (arr (pt !followsymlinks) nil) char (arr-decl (str "-f") (str "-follow-symlinks") !null))
(const (arr (pt !humanreadable) nil)  char (arr-decl (str "-h") (str "-human-readable")  !null))
(const (arr (pt !recursive) nil)      char (arr-decl (str "-r") (str "-recursive")       !null))

(func atoi-if int (((pt c) char))
	(if (not c)
		(return -1))
	(return (@atoi c)))

(define !bufsize 256)
(var (arr buffer !bufsize) char)

(func modeify void (x)
	(var (arr ret 10) char (str "drwxrwxrwx"))
	(var i int 9)
	(if (not (call !s-isdir x))
		(set (nth ret 0) (char "-")))
	(while (ge i 1)
		(if (same (mod x 2) 0)
			(set (nth ret i) (char "-")))
		(div-eq x 2)
		(pdec i))
	(for (set i 0) (lt i 10) (inc i)
		(@putchar (nth ret i)))
	(@putchar (char "\\t")))

(func printhumansize int (x)
	(var size float (^x float))
	(var (pt (arr prefixes nil)) char
		(arr-decl (str !b) (str !kb) (str !mb) (str !tb) (str !pb)))
	(var i int 0)
	(while (gt size 1024)
		(div-eq size 1024)
		(pinc i))
	(@printf (str "%.2g%s\\t") size (nth prefixes i)))

(func (pt stradd) char (((const (pt a) char) nil) ((const (pt b) char) nil))
	(var (pt c) char (@malloc (add (@strlen a) (@strlen b) 1)))
	(@memcpy c a (@strlen a))
	(@memcpy (add c (@strlen a)) b (add (@strlen b) 1))
	(return c))

(typedef (struct -ll (
	((pt next) (struct -ll))
	((pt data) void))) ll)

(func lsdir void (
	((pt path) char)
	(classify char)
	(longlisting char)
	(followsymlinks char)
	(humanreadable char)
	(recursive char))

	(var (pt dir) !dir (@opendir path))
	(if (not dir) (return))

	(var dirstat (struct stat))
	(var (pt dirinfo) dirent)
	(var (pt nextlistings) ll)
	(var (pt tmp) ll)

	(while (set dirinfo (@readdir dir))
		(@stat (slot dirinfo d-name) (addr dirstat))
		(@printf (str "%-12s\\t") (slot dirinfo d-name))
		(if recursive
			(if (and (eq (slot dirinfo d-type) !dt-dir)
				(or (eq (slot dirinfo d-type) !dt-lnk) followsymlinks))
				(if (and
					(@strcmp (slot dirinfo d-name) (str "."))
					(@strcmp (slot dirinfo d-name) (str "..")))
					(progn
						(set tmp nextlistings)
						(set nextlistings (@malloc (@sizeof ll)))
						(set (slot nextlistings data)
									(@stradd (@stradd path (str /)) (slot dirinfo d-name)))
						(set (slot nextlistings next) tmp)))))

		(if classify
			(progn
				(@!chifelse (eq (slot dirinfo d-type) !dt-dir)
					(char /) (char " "))
				(@!chifelse (@!execinfop (mem dirstat st-mode))
					(char *) (char " "))
				(@!chifelse (eq (slot dirinfo d-type) !dt-lnk)
					(char @) (char " "))))
		(if longlisting
			(progn
				(@printf (str %d\\t) (slot dirinfo d-ino))
				(@modeify (mem dirstat st-mode))
				(var (pt uid) (struct passwd) (@getpwuid (mem dirstat st-uid)))
				(var (pt gid) (struct group)  (@getgrgid (mem dirstat st-uid)))
				(@printf (str %s\\t) (? uid (slot uid pw-name) (str root)))
				(@printf (str %s\\t) (? gid (slot gid gr-name) (str root)))
				(if humanreadable
					(@printhumansize (mem dirstat st-size))
					(@printf (str %d\\t) (mem dirstat st-size)))

				(var (pt yearboundary) (struct tm))
				(var rawtime time_t (@time 0))
				(set yearboundary (@localtime (addr rawtime)))
				(set (slot yearboundary tm-yday) 0)
				(set (slot yearboundary tm-mon ) 0)
				(set (slot yearboundary tm-mday) 0)
				(set (slot yearboundary tm-sec ) 0)
				(set (slot yearboundary tm-min ) 0)
				(set (slot yearboundary tm-hour) 0)
				(if (lt (mem dirstat st-mtime) (@mktime yearboundary))
					(@strftime
						buffer
						!bufsize
						(str "%b %d %Y")
						(@localtime (addr (mem dirstat st-mtime))))
					(@strftime
						buffer
						!bufsize
						(str "%b %d %H:%M")
						(@localtime (addr (mem dirstat st-mtime)))))
				(@printf (str "%s ") buffer)))
		(@putchar (char \\n))
		(while nextlistings
			(@printf (str "\\n%s:\\n")
				(cast (slot nextlistings data) (typ* char 2)))
			(@lsdir
				(cast (slot nextlistings data) (typ* char 2))
				classify longlisting followsymlinks humanreadable recursive)
			(set nextlistings (slot nextlistings next)))))
(main
	(var pos int 0)
	(var diskusage int -1)
	(set diskusage
		(@atoi-if
			(@parse-arg argv (^!diskusage (typ* char 2)) true (addr pos))))
	(templates buffers-set (x y)
		(var x char (@!buffer (@parse-arg argv (cast y (typ* char 2)) false (addr pos)))))
	(buffers-set
		(classify !classify)
		(longlisting !longlisting)
		(followsymlinks !followsymlinks)
		(humanreadable !humanreadable)
		(recursive !recursive))
	(var (pt path) char (? (eq pos (- argc 1)) (str ".") (nth argv (- argc 1))))
	(@lsdir path classify longlisting followsymlinks humanreadable recursive)
	(return 0))

error: pathspec 'myls.cl' did not match any file(s) known to git


sketched RigidMolecule.cl; no testing; not even tried to compile

#define R2SAFE 1.0e-2
#define F2MAX  10.0

#define R_MAX  1.8
#define R2MAX  3.24

float2 pair_force( float2 p1, float2 p2 ){
    float2 d   = p2 - p1;
    float  r2  = dot(d,d);
    if( r2 > R2MAX ) return (float2) (0.0f, 0.0f);
    float ir2 = 1/( r2 + R2SAFE );
    float fr  = (0.7-ir2)*(R2MAX-r2);
    return d * fr;
}

__kernel void NBody_force(
    unsigned int num,
    __global float2* pos,
    __global float2* force
){
    const int iG = get_global_id (0);
    const int iL = get_local_id  (0);
    const int nL = get_local_size(0);
    __local  float2 pos_shared[64];
    float2 p = pos[iG];
    float2 f = (float2) (0.0f, 0.0f);
    for (int i0=0; i0<num; i0+= nL ){
        pos_shared[iL] = pos[i0 + iL];
        barrier(CLK_LOCAL_MEM_FENCE);  // wait for loading all  pos_shared[iL]
        for (int j=0; j<nL; j++){
            float2 pj  = pos_shared[j];
            f         += pair_force( p, pj );
        }
        barrier(CLK_LOCAL_MEM_FENCE);  // block writing new     pos_shared[iL] before inner loop finished
    }
    force[iG] = f;
}

float4 Quat_forceFromPoint( float4 q, float3 p, float3 fp ){

	float4 fq;
	float3 b;
	b.x =    p.y*q.y +               p.z*q.z;
	b.y =    p.x*q.y - 2*p.y*q.x +   p.z*q.w;
	b.z =    p.x*q.z -   p.y*q.w - 2*p.z*q.x;
	fq.x = dot(fp,b);

	b.x = -2*p.x*q.y +   p.y*q.x -   p.z*q.w;
	b.y =    p.x*q.x +               p.z*q.z;
	b.z =    p.x*q.w +   p.y*q.z - 2*p.z*q.y;
	fq.y = dot(fp,b);

	b.x = -2*p.x*q.z +   p.y*q.w +   p.z*q.x;
	b.y =   -p.x*q.w - 2*p.y*q.z +   p.z*q.y;
	b.z =    p.x*q.x +   p.y*q.y;
	fq.z = dot(fp,b);

	b.x =    p.y*q.z - p.z*q.y;
	b.y =   -p.x*q.z + p.z*q.x;
	b.z =    p.x*q.y - p.y*q.x;
	fq.w = dot(fp,b);
	return fq;
}

float4 Quat_qmul( float4 a, float4 b) {  // 16 mul, 12 add
    return (float4)(
      b.x * a.w + b.y * a.z - b.z * a.y + b.w * a.x ,
     -b.x * a.z + b.y * a.w + b.z * a.x + b.w * a.y ,
      b.x * a.y - b.y * a.x + b.z * a.w + b.w * a.z ,
     -b.x * a.x - b.y * a.y - b.z * a.z + b.w * a.w );
};

float3 Quat_transformVec( float4 q, float3 p){
    return Quat_qmul( q, Quat_qmul( (float4)(q,0), q) );   // 32 mul, 24 add ... using matrix it would be faster (9 mul) (?)
}

float8 transformMol( int na, int nb, __local float4* atomsA, __local float4* atomsB ){
    float8 f;
    for(int i=0; i<na; i++){
        float3 pi = atomsA[i];
        float3 fi = 0.0f;
        for(int j=0; j<na; j++){
             fi += pair_force( pi, atomsB[j] );
        }
        Quat_forceFromPoint( q, pi, fp );
    }
    return f;
}

float8 transformMol( float8 trans, int n,  __local float4* fromAtom, __local float4* toAtoms ){
    for(int i=0; i<n; i++){ toAtoms[i] = Quat_transformVec( trans.hi, fromAtom[i] ) + trans.xyz; }
}

__kernel void RigidMolForce(
    int nAtoms,
    __global float8* pos,    // pos,quat
    __global float8* force,
    __const float4 AtomsInMol
){
    const int iG = get_global_id (0);
    const int iL = get_local_id  (0);
    const int nL = get_local_size(0);
    __local           Lpos[16];
    __local  float4 Latoms[16];
    __local  float4 atomsA[16];
    private  float4 atomsB[16]; // do we have enought memory for this ?
    Latoms[iL] = AtomsInMol[iL];
    barrier(CLK_LOCAL_MEM_FENCE);
    float8 p = pos[iG];
    float8 f = 0.0f;
    transformMol( p, nAtoms, Latoms, atomsB);
    for (int i0=0; i0<get_local_size(0); i0+= nL ){
        Lpos[iL] = pos[i0 + iL];
        barrier(CLK_LOCAL_MEM_FENCE);
        for (int j=0; j<nL; j++){
            transformMolMol( Lpos[j], nAtoms, Latoms, atomsB);
            f    += forceFromMol( nAtoms, nAtoms, atomsA, atomsB );
        }
        barrier(CLK_LOCAL_MEM_FENCE);
    }
    force[iG] = f;
}

error: pathspec 'cpp/sketches_OCL/NBody/cl/RigidMolecule.cl' did not match any file(s) known to git


Simplify test case

Simplify test case


Create collatzPreCalc.cl

Create collatzPreCalc.cl

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/SosirisTseng/collatz-opencl.git/'


Added 'idock uses MWC64X'

Added 'idock uses MWC64X'

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/HongjianLi/idock.git/'


Initial version.

Initial version.

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

//#include "cl_random.hcl"
//#include <stdio.h>

/* rng/taus.c
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/*
 * The following adapted from rng/taus.c by Craig Rasmussen, 12/27/2010
 * for OpenCL.  Also converted (hopefully) to use 32 bit integers.
 *
 * It uses a uint4 to store state and a result:
 *    state.s0 => random number
 *    state.s1 => state s1 value
 *    state.s2 => state s2 value
 *    state.s3 => state s3 value
 */

//#include "../arch/opencl/pv_opencl.h"

#define CL_KERNEL     __kernel
#define CL_MEM_GLOBAL __global
#define CL_MEM_LOCAL  __local

static inline uint4
cl_random_state(uint4 state)
{
#define TAUSWORTHE(s,a,b,c,d) (((s &c) <<d)) ^ ((((s <<a))^s) >>b)

  state.s1 = TAUSWORTHE (state.s1, 13, 19, 4294967294, 12);
  state.s2 = TAUSWORTHE (state.s2,  2, 25, 4294967288, 4);
  state.s3 = TAUSWORTHE (state.s3,  3, 11, 4294967280, 17);

  state.s0 = (state.s1 ^ state.s2 ^ state.s3);

  return state;
}

static inline float cl_random_prob(uint4 state)
{
   return (float) ((double) state.s0 / (double) 4294967296.0);
}

//
// get new set of random numbers
//
//    assume called with 1D kernel
//
CL_KERNEL
void cl_rand (
    const int nx,
    const int ny,
    const int nf,
    const int nb,
    CL_MEM_GLOBAL uint4 * rnd)
{
   int l = get_global_id(0);

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

   // load local variables from global memory
   //
   uint4 l_rnd = rnd[l];

   l_rnd = cl_random_state(l_rnd);

   // store local variables back to global memory
   //
   rnd[l] = l_rnd;
}

error: pathspec 'tests/kernels/test_cl_random.cl' did not match any file(s) known to git


added the kernel file

added the kernel file

__kernel void ScaleTensor(global MIOPEN_TYPE * __restrict dst, MIOPEN_ALPHA_TYPE alpha, long num_elems)
{
    uint gid = get_global_id(0);
    if(gid < num_elems) {
        dst[gid] *= alpha;
    }
}

__kernel void SetTensor(global MIOPEN_TYPE * __restrict dst, MIOPEN_ALPHA_TYPE alpha, long num_elems)
{
    uint gid = get_global_id(0);
    if(gid < num_elems) {
        dst[gid] = alpha;
    }
}

error: pathspec 'src/Kernels/MIOpenTensorScaleKernel.cl' did not match any file(s) known to git


Added __local const to shared separation variables


Create EFIT2D.cl

Create EFIT2D.cl

OpenCL Kernels, Elastic EFIT2D

/** Source Input Kernel
*/
__kernel void Source_EFIT2D( __global float *Txx,__global float *Tyy, __global const int *XL, __global const int *YL, const float source){

			  uint i =	get_global_id(0);
			  Txx[ind(XL[i],YL[i])] -= source;
		  	  Tyy[ind(XL[i],YL[i])] -= source;

}

/** Receiver Kernel
*/
__kernel void Receiver_EFIT2D( __global float *Txx, __global float *receiver, const int t,
							   __global const int *XXL, __global const int *YYL){

			   float _tmp = 0.0f;

			   for (int i=0; i<get_global_size(0); ++i)
		       {
				 _tmp +=  Txx[ind(XXL[i],YYL[i])];
			   }

			   receiver[t] = _tmp/(float)get_global_size(0);

}

/** Velocity Kernel (Global Memory) for Elastic Case
*/
__kernel void Velocity_EFIT2D(__global float *Txx, __global float *Txy, __global float *Tyy,
							  __global float *vx,  __global float *vy,
							  __global const float *BX,	__global const float *BY,
							  __global const float *ABS){

		int j = get_global_id(0);
		int i = get_global_id(1);

	    if (i<MRI-1 && j>0){
			vx[ind(i,j)]  += (BX[ind(i,j)]*dtx)*( Txx[ind(i+1,j)] - Txx[ind(i,j)]	 + Txy[ind(i,j)]   - Txy[ind(i,j-1)] );
	    }

	    if (i>0 &&  j<NRI-1){
			vy[ind(i,j)] += (BY[ind(i,j)]*dtx)*( Txy[ind(i,j)]   - Txy[ind(i-1,j)] + Tyy[ind(i,j+1)] - Tyy[ind(i,j)]		 );

	    }

	    barrier(CLK_GLOBAL_MEM_FENCE);
		// Apply absorbing boundary conditions

		vx[ind(i,j)]	  *= ABS[ind(i,j)];
 	   	vy[ind(i,j)]	  *= ABS[ind(i,j)];
	 }

/** Stress Kernel (Global Memory) for Elastic Case
*/
__kernel void Stress_EFIT2D(__global float *Txx, __global float *Txy, __global float *Tyy,
							__global float *vx,	 __global float *vy,
							__global const float *C11,  __global const float *C12, __global const float *C44,
							__global const float *ABS) {

		int j = get_global_id(0);
 		int i = get_global_id(1);

 		if (i>0 && j>0 ){
				 Txx[ind(i,j)] += ( ( C11[ind(i,j)]* dtx )*(vx[ind(i,j)] - vx[ind(i-1,j)]) +
									( C12[ind(i,j)]* dtx )*(vy[ind(i,j)] - vy[ind(i,j-1)]) );

				 Tyy[ind(i,j)] += (	( C12[ind(i,j)]* dtx )*(vx[ind(i,j)] - vx[ind(i-1,j)]) +
									( C11[ind(i,j)]* dtx )*(vy[ind(i,j)] - vy[ind(i,j-1)]) );
       	}

 		if (i<MRI-1  && j<NRI-1){
				 Txy[ind(i,j)] +=	( C44[ind(i,j)]	 * dtx )*(vx[ind(i,j+1)] - vx[ind(i,j)] + vy[ind(i+1,j)] - vy[ind(i,j)] ) ;
 		}

 		barrier(CLK_GLOBAL_MEM_FENCE);

 		Txx[ind(i,j)]	*= ABS[ind(i,j)];
 		Tyy[ind(i,j)]	*= ABS[ind(i,j)];
 		Txy[ind(i,j)]	*= ABS[ind(i,j)];

}

/** Velocity Kernel (Local Memory) for Elastic Case
*/

__kernel void Velocity_Local(__global float *Txx, __global float *Txy, __global float *Tyy,
						     __global float *vx,  __global float *vy,
							 __global const float *BX, __global const float *BY, __global const float *ABS){

	 __local float local_Txx[DimLocalX+Stencil][DimLocalY+Stencil];
	 __local float local_Txy[DimLocalX+Stencil][DimLocalY+Stencil];
	 __local float local_Tyy[DimLocalX+Stencil][DimLocalY+Stencil];

	 uint halo = Stencil/2;
	 uint j	   = get_group_id(0) * get_local_size(0) + get_local_id(0);
	 uint i	   = get_group_id(1) * get_local_size(1) + get_local_id(1);

	 uint iBlock   = get_local_id(1)+halo;
	 uint jBlock   = get_local_id(0)+halo;

	 uint iField   = i + halo;
	 uint jField   = j + halo;

	 float D_Txx  = 0.0f;
	 float Dx_Txy = 0.0f;
	 float Dy_Txy = 0.0f;
	 float D_Tyy  = 0.0f;

	 float tabs, tdvx, tdvy, tvx, tvy;

     if (i <  MRI - Stencil && j < NRI - Stencil ){

      		   barrier(CLK_LOCAL_MEM_FENCE);

			   // fill left halo of local memory
			   if (get_local_id(0) < halo )
			   {
							 local_Txx[iBlock][jBlock-halo] = Txx[iField*NRI + jField - halo];
							 local_Tyy[iBlock][jBlock-halo] = Tyy[iField*NRI + jField - halo];
							 local_Txy[iBlock][jBlock-halo] = Txy[iField*NRI + jField - halo];

			   }

			   // fill right halo of local memory
			   if (get_local_id(0) > DimLocalY - halo -1 )
			   {
							 local_Txx[iBlock][jBlock+halo] = Txx[iField*NRI + jField + halo];
							 local_Tyy[iBlock][jBlock+halo] = Tyy[iField*NRI + jField + halo];
							 local_Txy[iBlock][jBlock+halo] = Txy[iField*NRI + jField + halo];

			   }

			   // fill bottom halo of local memory
			   if (get_local_id(1) < halo )
			   {
							 local_Txx[iBlock-halo][jBlock] = Txx[(iField-halo)*NRI + jField];
							 local_Tyy[iBlock-halo][jBlock] = Tyy[(iField-halo)*NRI + jField];
							 local_Txy[iBlock-halo][jBlock] = Txy[(iField-halo)*NRI + jField];

			   }

			   // fill top halo of local memory
			   if (get_local_id(1) > DimLocalX - halo -1 )
			   {
							 local_Txx[iBlock+halo][jBlock] = Txx[(iField+halo)*NRI + jField];
							 local_Tyy[iBlock+halo][jBlock] = Tyy[(iField+halo)*NRI + jField];
							 local_Txy[iBlock+halo][jBlock] = Txy[(iField+halo)*NRI + jField];

			   }

			   local_Txx[iBlock][jBlock]		= Txx[iField*NRI + jField];
			   local_Tyy[iBlock][jBlock]		= Tyy[iField*NRI + jField];
			   local_Txy[iBlock][jBlock]		= Txy[iField*NRI + jField];

                barrier(CLK_LOCAL_MEM_FENCE);

				D_Txx  = 0.0f;
				Dx_Txy = 0.0f;
				Dy_Txy = 0.0f;
				D_Tyy  = 0.0f;

				if (j!=0){
				    Dy_Txy = local_Txy[iBlock][jBlock] - local_Txy[iBlock][jBlock-1];
				}

				if (i!=0){
				    Dx_Txy = local_Txy[iBlock][jBlock] - local_Txy[iBlock-1][jBlock];
				}

				D_Txx	 = local_Txx[iBlock+1][jBlock]	- local_Txx[iBlock][jBlock];
				D_Tyy	 = local_Tyy[iBlock][jBlock+1]	- local_Tyy[iBlock][jBlock];

				tvx = vx[iField*NRI + jField];
			    tvy = vy[iField*NRI + jField];

				tvx += (BX[iField*NRI+jField]*(dtx))*( D_Txx	 +	Dy_Txy );
				tvy += (BY[iField*NRI+jField]*(dtx))*( Dx_Txy	 +	D_Tyy  );

			   tabs = ABS[iField*NRI + jField];
			   vx[iField*NRI + jField]		= tvx*tabs;
			   vy[iField*NRI + jField]		= tvy*tabs;
    }

}

/** Stress Kernel (Local Memory) for Elastic Case
*/

__kernel void Stress_Local(__global float *Txx,  __global float *Txy,  __global float *Tyy,
						   __global float *vx,   __global float *vy,
						   __global const float *C11, __global const float *C12, __global const float *C44,
						   __global const float *ABS){

		 __local  float local_vx[DimLocalX+Stencil][DimLocalY+Stencil];
		 __local  float local_vy[DimLocalX+Stencil][DimLocalY+Stencil];
		 __local  float local_ABS[DimLocalX+Stencil][DimLocalY+Stencil];

		 uint halo = Stencil/2;
		 uint j	   = get_group_id(0) * get_local_size(0) + get_local_id(0);
		 uint i	   = get_group_id(1) * get_local_size(1) + get_local_id(1);

		 uint iBlock			   = get_local_id(1)+halo;
		 uint jBlock			   = get_local_id(0)+halo;

		 uint iField			   = i + halo;
		 uint jField			   = j + halo;

		 float D_vx				  = 0.0f;
		 float D_vy				  = 0.0f;
		 float Dy_vx			  = 0.0f;
		 float Dx_vy			  = 0.0f;

		float tabs,tTxx, tTyy, tTxy;

		  if (i <  MRI - Stencil && j < NRI - Stencil ){

				barrier(CLK_LOCAL_MEM_FENCE);

				// fill left halo of local memory
				if (get_local_id(0) < halo )
				{
							  local_vx[iBlock][jBlock-halo]  = vx[iField*NRI + jField - halo];
							  local_vy[iBlock][jBlock-halo]  = vy[iField*NRI + jField - halo];

				}

				// fill right halo of local memory
				if (get_local_id(0) > DimLocalY - halo -1 )
				{
							  local_vx[iBlock][jBlock+halo]  = vx[iField*NRI + jField + halo];
							  local_vy[iBlock][jBlock+halo]  = vy[iField*NRI + jField + halo];

				}

				// fill bottom halo of local memory
				if (get_local_id(1) < halo )
				{
							  local_vx[iBlock-halo][jBlock]  = vx[(iField-halo)*NRI + jField];
							  local_vy[iBlock-halo][jBlock]  = vy[(iField-halo)*NRI + jField];

				}

				// fill top halo of local memory
				if (get_local_id(1) > DimLocalX - halo -1 )
				{
							  local_vx[iBlock+halo][jBlock]  = vx[(iField+halo)*NRI + jField];
							  local_vy[iBlock+halo][jBlock]  = vy[(iField+halo)*NRI + jField];

				}

				local_vx[iBlock][jBlock]  = vx[iField*NRI + jField];
				local_vy[iBlock][jBlock]  = vy[iField*NRI + jField];

				barrier(CLK_LOCAL_MEM_FENCE);

				D_vx   = 0.0f;
				D_vy   = 0.0f;
				Dy_vx  = 0.0f;
				Dx_vy  = 0.0f;

				if (i!= 0){
							 D_vx = local_vx[iBlock][jBlock]- local_vx[iBlock-1][jBlock];
				}

				if (j!=0){
							 D_vy = local_vy[iBlock][jBlock]- local_vy[iBlock][jBlock-1];
				}

				 Dy_vx = local_vx[iBlock][jBlock+1] - local_vx[iBlock][jBlock];
				 Dx_vy = local_vy[iBlock+1][jBlock] - local_vy[iBlock][jBlock];

				 tTxx = Txx[iField*NRI + jField];
				 tTyy = Tyy[iField*NRI + jField];
				 tTxy = Txy[iField*NRI + jField];

				 tTxx += (C11[iField*NRI + jField]*dtx)*D_vx + (C12[iField*NRI + jField]*dtx)*D_vy ;
				 tTyy += (C12[iField*NRI + jField]*dtx)*D_vx + (C11[iField*NRI + jField]*dtx)*D_vy ;
				 tTxy += (C44[iField*NRI + jField]*dtx)*( Dx_vy + Dy_vx );

				 tabs = ABS[iField*NRI + jField];

				 Txx[iField*NRI + jField]	= tTxx *  tabs;
				 Tyy[iField*NRI + jField]   = tTyy * tabs;
				 Txy[iField*NRI + jField]	= tTxy * tabs;
          }

}

error: pathspec 'EFIT2D.cl' did not match any file(s) known to git


Initial version.

Initial version.

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

/* rng/taus.c
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/*
 * The following adapted from rng/taus.c by Craig Rasmussen, 12/27/2010
 * for OpenCL.  Also converted (hopefully) to use 32 bit integers.
 *
 * It uses a uint4 to store state and a result:
 *    state.s0 => random number
 *    state.s1 => state s1 value
 *    state.s2 => state s2 value
 *    state.s3 => state s3 value
 */

#define cl_random_state(s) (cl_taus_get(s))

#ifndef PF_USE_OPENCL
   typedef struct uint4_ {
      int s0, s1, s2, s3;
   } uint4;
#endif

static inline uint4
cl_taus_get(uint4 state)
{
   uint4 result;

#define TAUSWORTHE(s,a,b,c,d) (((s &c) <<d)) ^ ((((s <<a))^s) >>b)

  result.s1 = TAUSWORTHE (state.s1, 13, 19, 4294967294UL, 12);
  result.s2 = TAUSWORTHE (state.s2,  2, 25, 4294967288UL, 4);
  result.s3 = TAUSWORTHE (state.s3,  3, 11, 4294967280UL, 17);

  result.s0 = (state.s1 ^ state.s2 ^ state.s3);

  return result;
}

static inline float cl_random_prob(uint4 state)
{
   return (float) ((double) state.s0 / (double) 4294967296.0);
}

error: pathspec 'src/kernels/cl_random.cl' did not match any file(s) known to git


Practice with using macros, [note] the `cond1` implementation is not right, do NOT use it

;; @file macros.cl
;;
;; @breif Examples using macros
;;

; `progn` implementation with lambda function
(defmacro progn1 (&rest body)
  `(funcall (lambda () ,@body)))
; `when` macro
(defmacro when1 (condition &rest body)
  `(if ,condition (progn1 ,@body)))
; `unless` macro
(defmacro unless1 (condition &rest body)
  `(if (not ,condition) (progn1 ,@body)))
; `cond` macro
(defmacro cond1 (&rest branches)
  `(dolist (branch ,branches)
    (let ((condition (pop branch)) (body branch))
      (if condition (progn @body) break))))

error: pathspec 'macros.cl' did not match any file(s) known to git


Fixed Retina_update_state name and parameters to be consistent.

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

#include "Retina_params.h"
#include "cl_random.hcl"

#ifndef PI
#  define PI 3.1415926535897932
#endif

#ifndef PV_USE_OPENCL

#  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
#  include "conversions.hcl"

#endif /* PV_USE_OPENCL */

/*
 * 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
   }

   int spike_flag = (cl_random_prob(*rnd_state) < probSpike);
   *rnd_state = cl_random_state(*rnd_state);
   return spike_flag;
}

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

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

    CL_MEM_GLOBAL Retina_params * params,
    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 = (float) 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
   //
   rnd[k] = l_rnd;
   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.hcl"

#ifndef PI
#  define PI 3.1415926535897932
#endif

#ifndef PV_USE_OPENCL

#  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
#  include "conversions.hcl"

#endif /* PV_USE_OPENCL */

/*
 * 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
   }

   int spike_flag = (cl_random_prob(*rnd_state) < probSpike);
   *rnd_state = cl_random_state(*rnd_state);
   return spike_flag;
}

//
// 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 = (float) 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
   //
   rnd[k] = l_rnd;
   phiExc[k] = l_phiExc;
   phiInh[k] = l_phiInh;
   prevTime[kex] = l_prev;
   activity[kex] = l_activ;

#ifndef PV_USE_OPENCL
   }
#endif

}


Add specialized copysign implementation

Add specialized copysign implementation

/* OpenCL built-in library: copysign()

   Copyright (c) 2011 Universidad Rey Juan Carlos

   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.
*/

#if 0

#include "../templates.h"

// LLVM generates non-optimal code for this implementation
DEFINE_EXPR_V_VV(copysign,
                 ({
                   int bits = CHAR_BIT * sizeof(stype);
                   sjtype sign_mask = (sjtype)1 << (sjtype)(bits - 1);
                   sjtype result =
                     (~sign_mask & *(jtype*)&a) | (sign_mask & *(jtype*)&b);
                   *(vtype*)&result;
                 }))

#endif

#define IMPLEMENT_DIRECT(NAME, TYPE, EXPR)      \
  TYPE _cl_overloadable NAME(TYPE a, TYPE b)    \
  {                                             \
    return EXPR;                                \
  }

#define IMPLEMENT_UPCAST(NAME, TYPE, UPTYPE, LO)        \
  TYPE _cl_overloadable NAME(TYPE a, TYPE b)            \
  {                                                     \
    UPTYPE a1, b1;                                      \
    a1.LO = a;                                          \
    b1.LO = b;                                          \
    return NAME(a1, b1).LO;                             \
  }

#define IMPLEMENT_SPLIT(NAME, TYPE, LO, HI)             \
  TYPE _cl_overloadable NAME(TYPE a, TYPE b)            \
  {                                                     \
    return (TYPE)(NAME(a.LO, b.LO), NAME(a.HI, b.HI));  \
  }

#define IMPLEMENT_COPYSIGN_DIRECT                                       \
  ({                                                                    \
    int bits = CHAR_BIT * sizeof(stype);                                \
    jtype sign_mask = (jtype)1 << (jtype)(bits - 1);                    \
    jtype result = (~sign_mask & *(jtype*)&a) | (sign_mask & *(jtype*)&b); \
    *(vtype*)&result;                                                   \
  })
#define IMPLEMENT_COPYSIGN_SSE_FLOAT4                                   \
  ({                                                                    \
    uint4 sign_mask = {0x80000000U, 0x80000000U, 0x80000000U, 0x80000000U}; \
    __asm__ ("andps %[src], %[dst]" :                                   \
             [dst] "+x" (a) :                                           \
             [src] "xm" (~sign_mask));                                  \
    __asm__ ("andps %[src], %[dst]" :                                   \
             [dst] "+x" (b) :                                           \
             [src] "xm" (sign_mask));                                   \
    __asm__ ("orps %[src], %[dst]" :                                    \
             [dst] "+x" (a) :                                           \
             [src] "xm" (b));                                           \
    a;                                                                  \
  })
#define IMPLEMENT_COPYSIGN_AVX_FLOAT8                                   \
  ({                                                                    \
    uint8 sign_mask = {0x80000000U, 0x80000000U, 0x80000000U, 0x80000000U, \
                       0x80000000U, 0x80000000U, 0x80000000U, 0x80000000U}; \
    __asm__ ("andps256 %[src], %[dst]" :                                \
             [dst] "+x" (a) :                                           \
             [src] "xm" (~sign_mask));                                  \
    __asm__ ("andps256 %[src], %[dst]" :                                \
             [dst] "+x" (b) :                                           \
             [src] "xm" (sign_mask));                                   \
    __asm__ ("orps256 %[src], %[dst]" :                                 \
             [dst] "+x" (a) :                                           \
             [src] "xm" (b));                                           \
    a;                                                                  \
  })
#define IMPLEMENT_COPYSIGN_SSE2_DOUBLE2                                 \
  ({                                                                    \
    ulong2 sign_mask = {0x8000000000000000UL, 0x8000000000000000UL};    \
    __asm__ ("andpd %[src], %[dst]" :                                   \
             [dst] "+x" (a) :                                           \
             [src] "xm" (~sign_mask));                                  \
    __asm__ ("andpd %[src], %[dst]" :                                   \
             [dst] "+x" (b) :                                           \
             [src] "xm" (sign_mask));                                   \
    __asm__ ("orpd %[src], %[dst]" :                                    \
             [dst] "+x" (a) :                                           \
             [src] "xm" (b));                                           \
    a;                                                                  \
  })
#define IMPLEMENT_COPYSIGN_AVX_DOUBLE4                                  \
  ({                                                                    \
    ulong4 sign_mask = {0x8000000000000000UL, 0x8000000000000000UL,     \
                        0x8000000000000000UL, 0x8000000000000000UL};    \
    __asm__ ("andpd256 %[src], %[dst]" :                                \
             [dst] "+x" (a) :                                           \
             [src] "xm" (~sign_mask));                                  \
    __asm__ ("andpd256 %[src], %[dst]" :                                \
             [dst] "+x" (b) :                                           \
             [src] "xm" (sign_mask));                                   \
    __asm__ ("orpd256 %[src], %[dst]" :                                 \
             [dst] "+x" (a) :                                           \
             [src] "xm" (b));                                           \
    a;                                                                  \
  })

#ifdef __SSE__
IMPLEMENT_UPCAST(copysign, float  , float2, lo)
IMPLEMENT_UPCAST(copysign, float2 , float4, lo)
IMPLEMENT_UPCAST(copysign, float3 , float4, s012)
IMPLEMENT_DIRECT(copysign, float4 , IMPLEMENT_COPYSIGN_SSE_FLOAT4)
#  ifdef __AVX__
IMPLEMENT_DIRECT(copysign, float8 , IMPLEMENT_COPYSIGN_AVX_FLOAT8)
#  else
IMPLEMENT_SPLIT (copysign, float8 , lo, hi)
#  endif
IMPLEMENT_SPLIT (copysign, float16, lo, hi)
#else
IMPLEMENT_DIRECT(copysign, float  , IMPLEMENT_COPYSIGN_DIRECT)
IMPLEMENT_DIRECT(copysign, float2 , IMPLEMENT_COPYSIGN_DIRECT)
IMPLEMENT_DIRECT(copysign, float3 , IMPLEMENT_COPYSIGN_DIRECT)
IMPLEMENT_DIRECT(copysign, float4 , IMPLEMENT_COPYSIGN_DIRECT)
IMPLEMENT_DIRECT(copysign, float8 , IMPLEMENT_COPYSIGN_DIRECT)
IMPLEMENT_DIRECT(copysign, float16, IMPLEMENT_COPYSIGN_DIRECT)
#endif

#ifdef __SSE2__
IMPLEMENT_UPCAST(copysign, double  , double2, lo)
IMPLEMENT_DIRECT(copysign, double2 , IMPLEMENT_COPYSIGN_SSE2_DOUBLE2)
#  ifdef __AVX__
IMPLEMENT_UPCAST(copysign, double3 , double4, s012)
IMPLEMENT_DIRECT(copysign, double4 , IMPLEMENT_COPYSIGN_AVX_DOUBLE4)
#  else
IMPLEMENT_SPLIT (copysign, double3 , lo, s2)
IMPLEMENT_SPLIT (copysign, double4 , lo, hi)
#  endif
IMPLEMENT_SPLIT (copysign, double8 , lo, hi)
IMPLEMENT_SPLIT (copysign, double16, lo, hi)
#else
IMPLEMENT_DIRECT(copysign, double  , IMPLEMENT_COPYSIGN_DIRECT)
IMPLEMENT_DIRECT(copysign, double2 , IMPLEMENT_COPYSIGN_DIRECT)
IMPLEMENT_DIRECT(copysign, double3 , IMPLEMENT_COPYSIGN_DIRECT)
IMPLEMENT_DIRECT(copysign, double4 , IMPLEMENT_COPYSIGN_DIRECT)
IMPLEMENT_DIRECT(copysign, double8 , IMPLEMENT_COPYSIGN_DIRECT)
IMPLEMENT_DIRECT(copysign, double16, IMPLEMENT_COPYSIGN_DIRECT)
#endif

error: pathspec 'lib/kernel/x86_64/copysign.cl' did not match any file(s) known to git


add calc_addrs.cl from https://github.com/exploitagency/vanitygen-plus/blob/master/calc_addrs.cl a1d0b40d4c4168f14178dec147bb3b4f80d7e897

/*
 * Vanitygen, vanity bitcoin address generator
 * Copyright (C) 2011 <samr7@cs.washington.edu>
 *
 * Vanitygen is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * Vanitygen is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Vanitygen.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * This file contains an OpenCL kernel for performing certain parts of
 * the bitcoin address calculation process.
 *
 * Kernel: ec_add_grid
 *
 * Inputs:
 * - Row: Array of (sequential) EC points
 * - Column: Array of column increment EC points (= rowsize * Pgenerator)
 *
 * Steps:
 * - Compute P = Row[x] + Column[y]
 *   P is computed as numerator/denominator components Pxj, Pyj, Pz
 *   Final values are: Px = Pxj / (Pz^2), Py = Pyj / (Pz^3)
 *
 *   The modular inverse of Pz is required to compute Px and Py, and
 *   can be computed more efficiently in large batches.  This is done in
 *   the next kernel heap_invert.
 *
 * - Store Pxj, Pyj to intermediate point buffer
 * - Store Pz to z_heap
 *
 * Outputs:
 * - Intermediate point buffer
 * - Denominator buffer (z_heap)
 *
 * -------------------------------
 * Kernel: heap_invert
 *
 * Inputs:
 * - Denominator buffer (z_heap)
 * - N = Batch size (power of 2)
 *
 * Steps:
 * - Compute the product tree for N values in the denominator buffer
 * - Compute the modular inverse of the root of the product tree
 * - Multiply down the tree to compute the modular inverse of each leaf
 *
 * Outputs:
 * - Modular inverse denominator buffer (z_heap)
 *
 * -------------------------------
 * Kernel: hash_ec_point_get
 *
 * Inputs:
 * - Intermediate point buffer
 * - Modular inverse denominator buffer (z_heap)
 *
 * Steps:
 * - Compute Px = Pxj * (1/Pz)^2
 * - Compute Py = Pyj * (1/Pz)^3
 * - Compute H = RIPEMD160(SHA256({0x02|0x03|0x04} | Px | Py?))
 *
 * Output:
 * - Array of 20-byte address hash values
 *
 * -------------------------------
 * Kernel: hash_ec_point_search_prefix
 *
 * Like hash_ec_point_get, but instead of storing the complete hash
 * value to an output buffer, it searches a sorted list of ranges,
 * and if a match is found, writes a flag to an output buffer.
 */

/* Byte-swapping and endianness */
#define bswap32(v)					\
	(((v) >> 24) | (((v) >> 8) & 0xff00) |		\
	 (((v) << 8) & 0xff0000) | ((v) << 24))

#if __ENDIAN_LITTLE__ != 1
#define load_le32(v) bswap32(v)
#define load_be32(v) (v)
#else
#define load_le32(v) (v)
#define load_be32(v) bswap32(v)
#endif

/* Configuration -- maybe I shouldn't be passing this in preproc */
#ifdef COMPRESSED_ADDRESS
	__constant bool compressed_address = 1;
#else
	__constant bool compressed_address = 0;
#endif

/*
 * Loop unrolling macros
 *
 * In most cases, preprocessor unrolling works best.
 * The exception is NVIDIA's compiler, which seems to take unreasonably
 * long to compile a loop with a larger iteration count, or a loop with
 * a body of >50 PTX instructions, with preprocessor unrolling.
 * However, it does not seem to take as long with pragma unroll, and
 * produces good output.
 */

/* Explicit loop unrolling */
#define unroll_5(a) do { a(0) a(1) a(2) a(3) a(4) } while (0)
#define unroll_8(a) do { a(0) a(1) a(2) a(3) a(4) a(5) a(6) a(7) } while (0)
#define unroll_1_7(a) do { a(1) a(2) a(3) a(4) a(5) a(6) a(7) } while (0)
#define unroll_7(a) do { a(0) a(1) a(2) a(3) a(4) a(5) a(6) } while (0)
#define unroll_7_0(a) do { a(7) a(6) a(5) a(4) a(3) a(2) a(1) a(0) } while (0)
#define unroll_7_1(a) do { a(7) a(6) a(5) a(4) a(3) a(2) a(1) } while (0)
#define unroll_16(a) do {				\
	a(0) a(1) a(2) a(3) a(4) a(5) a(6) a(7)		\
	a(8) a(9) a(10) a(11) a(12) a(13) a(14) a(15)	\
	} while (0)
#define unroll_64(a) do {				\
	a(0) a(1) a(2) a(3) a(4) a(5) a(6) a(7)		\
	a(8) a(9) a(10) a(11) a(12) a(13) a(14) a(15)	\
	a(16) a(17) a(18) a(19) a(20) a(21) a(22) a(23) \
	a(24) a(25) a(26) a(27) a(28) a(29) a(30) a(31)	\
	a(32) a(33) a(34) a(35) a(36) a(37) a(38) a(39) \
	a(40) a(41) a(42) a(43) a(44) a(45) a(46) a(47) \
	a(48) a(49) a(50) a(51) a(52) a(53) a(54) a(55) \
	a(56) a(57) a(58) a(59) a(60) a(61) a(62) a(63) \
	} while (0)

/* Conditional loop unrolling */
#if defined(DEEP_PREPROC_UNROLL)
#define iter_5(a) unroll_5(a)
#define iter_8(a) unroll_8(a)
#define iter_16(a) unroll_16(a)
#define iter_64(a) unroll_64(a)
#else
#define iter_5(a) do {int _i; for (_i = 0; _i < 5; _i++) { a(_i) }} while (0)
#define iter_8(a) do {int _i; for (_i = 0; _i < 8; _i++) { a(_i) }} while (0)
#define iter_16(a) do {int _i; for (_i = 0; _i < 16; _i++) { a(_i) }} while (0)
#define iter_64(a) do {int _i; for (_i = 0; _i < 64; _i++) { a(_i) }} while (0)
#endif

/*
 * BIGNUM mini-library
 * This module deals with fixed-size 256-bit bignums.
 * Where modular arithmetic is performed, the SECP256k1 prime
 * modulus (below) is assumed.
 *
 * Methods include:
 * - bn_is_zero/bn_is_one/bn_is_odd/bn_is_even/bn_is_bit_set
 * - bn_rshift[1]/bn_lshift[1]
 * - bn_neg
 * - bn_uadd/bn_uadd_p
 * - bn_usub/bn_usub_p
 */

typedef uint bn_word;
#define BN_NBITS 256
#define BN_WSHIFT 5
#define BN_WBITS (1 << BN_WSHIFT)
#define BN_NWORDS ((BN_NBITS/8) / sizeof(bn_word))
#define BN_WORDMAX 0xffffffff

#define MODULUS_BYTES \
	0xfffffc2f, 0xfffffffe, 0xffffffff, 0xffffffff, \
	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff

typedef struct {
	bn_word d[BN_NWORDS];
} bignum;

__constant bn_word modulus[] = { MODULUS_BYTES };
__constant bignum bn_zero = {{0x0}};

__constant bn_word mont_rr[BN_NWORDS] = { 0xe90a1, 0x7a2, 0x1, 0, };
__constant bn_word mont_n0[2] = { 0xd2253531, 0xd838091d };

#define bn_is_odd(bn)		(bn.d[0] & 1)
#define bn_is_even(bn) 		(!bn_is_odd(bn))
#define bn_is_zero(bn) 		(!bn.d[0] && !bn.d[1] && !bn.d[2] && \
				 !bn.d[3] && !bn.d[4] && !bn.d[5] && \
				 !bn.d[6] && !bn.d[7])
#define bn_is_one(bn) 		((bn.d[0] == 1) && !bn.d[1] && !bn.d[2] && \
				 !bn.d[3] && !bn.d[4] && !bn.d[5] && \
				 !bn.d[6] && !bn.d[7])
#define bn_is_bit_set(bn, n) \
	((((bn_word*)&bn)[n >> BN_WSHIFT]) & (1 << (n & (BN_WBITS-1))))

#define bn_unroll(e) unroll_8(e)
#define bn_unroll_sf(e)	unroll_1_7(e)
#define bn_unroll_sl(e)	unroll_7(e)
#define bn_unroll_reverse(e) unroll_7_0(e)
#define bn_unroll_reverse_sl(e) unroll_7_1(e)

#define bn_unroll_arg(e, arg)				\
	e(arg, 0) e(arg, 1) e(arg, 2) e(arg, 3)	\
	e(arg, 4) e(arg, 5) e(arg, 6) e(arg, 7)
#define bn_unroll_arg_sf(e, arg)			\
	e(arg, 1) e(arg, 2) e(arg, 3)		\
	e(arg, 4) e(arg, 5) e(arg, 6) e(arg, 7)

#define bn_iter(e) iter_8(e)

/*
 * Bitwise shift
 */

void
bn_lshift1(bignum *bn)
{
#define bn_lshift1_inner1(i)						\
		bn->d[i] = (bn->d[i] << 1) | (bn->d[i-1] >> 31);
	bn_unroll_reverse_sl(bn_lshift1_inner1);
	bn->d[0] <<= 1;
}

void
bn_rshift(bignum *bn, int shift)
{
	int wd, iws, iwr;
	bn_word ihw, ilw;
	iws = (shift & (BN_WBITS-1));
	iwr = BN_WBITS - iws;
	wd = (shift >> BN_WSHIFT);
	ihw = (wd < BN_WBITS) ? bn->d[wd] : 0;

#define bn_rshift_inner1(i)				\
		wd++;					\
		ilw = ihw;				\
		ihw = (wd < BN_WBITS) ? bn->d[wd] : 0;	\
		bn->d[i] = (ilw >> iws) | (ihw << iwr);
	bn_unroll_sl(bn_rshift_inner1);
	bn->d[BN_NWORDS-1] = (ihw >> iws);
}

void
bn_rshift1(bignum *bn)
{
#define bn_rshift1_inner1(i)						\
		bn->d[i] = (bn->d[i+1] << 31) | (bn->d[i] >> 1);
	bn_unroll_sl(bn_rshift1_inner1);
	bn->d[BN_NWORDS-1] >>= 1;
}

void
bn_rshift1_2(bignum *bna, bignum *bnb)
{
#define bn_rshift1_2_inner1(i)						\
		bna->d[i] = (bna->d[i+1] << 31) | (bna->d[i] >> 1);	\
		bnb->d[i] = (bnb->d[i+1] << 31) | (bnb->d[i] >> 1);
	bn_unroll_sl(bn_rshift1_2_inner1);
	bna->d[BN_NWORDS-1] >>= 1;
	bnb->d[BN_NWORDS-1] >>= 1;
}

/*
 * Unsigned comparison
 */

int
bn_ucmp_ge(bignum *a, bignum *b)
{
	int l = 0, g = 0;

#define bn_ucmp_ge_inner1(i)				\
		if (a->d[i] < b->d[i]) l |= (1 << i);	\
		if (a->d[i] > b->d[i]) g |= (1 << i);
	bn_unroll_reverse(bn_ucmp_ge_inner1);
	return (l > g) ? 0 : 1;
}

int
bn_ucmp_ge_c(bignum *a, __constant bn_word *b)
{
	int l = 0, g = 0;

#define bn_ucmp_ge_c_inner1(i)				\
		if (a->d[i] < b[i]) l |= (1 << i);	\
		if (a->d[i] > b[i]) g |= (1 << i);
	bn_unroll_reverse(bn_ucmp_ge_c_inner1);
	return (l > g) ? 0 : 1;
}

/*
 * Negate
 */

void
bn_neg(bignum *n)
{
	int c = 1;

#define bn_neg_inner1(i)				\
		c = (n->d[i] = (~n->d[i]) + c) ? 0 : c;
	bn_unroll(bn_neg_inner1);
}

/*
 * Add/subtract
 */

#define bn_add_word(r, a, b, t, c) do {		\
		t = a + b;			\
		c = (t < a) ? 1 : 0;		\
		r = t;				\
	} while (0)

#define bn_addc_word(r, a, b, t, c) do {			\
		t = a + b + c;					\
		c = (t < a) ? 1 : ((c & (t == a)) ? 1 : 0);	\
		r = t;						\
	} while (0)

bn_word
bn_uadd_words_seq(bn_word *r, bn_word *a, bn_word *b)
{
	bn_word t, c = 0;

#define bn_uadd_words_seq_inner1(i)			\
		bn_addc_word(r[i], a[i], b[i], t, c);
	bn_add_word(r[0], a[0], b[0], t, c);
	bn_unroll_sf(bn_uadd_words_seq_inner1);
	return c;
}

bn_word
bn_uadd_words_c_seq(bn_word *r, bn_word *a, __constant bn_word *b)
{
	bn_word t, c = 0;

	bn_add_word(r[0], a[0], b[0], t, c);
	bn_unroll_sf(bn_uadd_words_seq_inner1);
	return c;
}

#define bn_sub_word(r, a, b, t, c) do {		\
		t = a - b;			\
		c = (a < b) ? 1 : 0;		\
		r = t;				\
	} while (0)

#define bn_subb_word(r, a, b, t, c) do {	\
		t = a - (b + c);		\
		c = (!(a) && c) ? 1 : 0;	\
		c |= (a < b) ? 1 : 0;		\
		r = t;				\
	} while (0)

bn_word
bn_usub_words_seq(bn_word *r, bn_word *a, bn_word *b)
{
	bn_word t, c = 0;

#define bn_usub_words_seq_inner1(i)			\
		bn_subb_word(r[i], a[i], b[i], t, c);

	bn_sub_word(r[0], a[0], b[0], t, c);
	bn_unroll_sf(bn_usub_words_seq_inner1);
	return c;
}

bn_word
bn_usub_words_c_seq(bn_word *r, bn_word *a, __constant bn_word *b)
{
	bn_word t, c = 0;

	bn_sub_word(r[0], a[0], b[0], t, c);
	bn_unroll_sf(bn_usub_words_seq_inner1);
	return c;
}

/*
 * Add/subtract better suited for AMD's VLIW architecture
 */
bn_word
bn_uadd_words_vliw(bn_word *r, bn_word *a, bn_word *b)
{
	bignum x;
	bn_word c = 0, cp = 0;

#define bn_uadd_words_vliw_inner1(i)		\
		x.d[i] = a[i] + b[i];

#define bn_uadd_words_vliw_inner2(i)			\
		c |= (a[i] > x.d[i]) ? (1 << i) : 0;	\
		cp |= (!~x.d[i]) ? (1 << i) : 0;

#define bn_uadd_words_vliw_inner3(i)		\
		r[i] = x.d[i] + ((c >> i) & 1);

	bn_unroll(bn_uadd_words_vliw_inner1);
	bn_unroll(bn_uadd_words_vliw_inner2);
	c = ((cp + (c << 1)) ^ cp);
	r[0] = x.d[0];
	bn_unroll_sf(bn_uadd_words_vliw_inner3);
	return c >> BN_NWORDS;
}

bn_word
bn_uadd_words_c_vliw(bn_word *r, bn_word *a, __constant bn_word *b)
{
	bignum x;
	bn_word c = 0, cp = 0;

	bn_unroll(bn_uadd_words_vliw_inner1);
	bn_unroll(bn_uadd_words_vliw_inner2);
	c = ((cp + (c << 1)) ^ cp);
	r[0] = x.d[0];
	bn_unroll_sf(bn_uadd_words_vliw_inner3);
	return c >> BN_NWORDS;
}

bn_word
bn_usub_words_vliw(bn_word *r, bn_word *a, bn_word *b)
{
	bignum x;
	bn_word c = 0, cp = 0;

#define bn_usub_words_vliw_inner1(i)		\
		x.d[i] = a[i] - b[i];

#define bn_usub_words_vliw_inner2(i)			\
		c |= (a[i] < b[i]) ? (1 << i) : 0;	\
		cp |= (!x.d[i]) ? (1 << i) : 0;

#define bn_usub_words_vliw_inner3(i)		\
		r[i] = x.d[i] - ((c >> i) & 1);

	bn_unroll(bn_usub_words_vliw_inner1);
	bn_unroll(bn_usub_words_vliw_inner2);
	c = ((cp + (c << 1)) ^ cp);
	r[0] = x.d[0];
	bn_unroll_sf(bn_usub_words_vliw_inner3);
	return c >> BN_NWORDS;
}

bn_word
bn_usub_words_c_vliw(bn_word *r, bn_word *a, __constant bn_word *b)
{
	bignum x;
	bn_word c = 0, cp = 0;

	bn_unroll(bn_usub_words_vliw_inner1);
	bn_unroll(bn_usub_words_vliw_inner2);
	c = ((cp + (c << 1)) ^ cp);
	r[0] = x.d[0];
	bn_unroll_sf(bn_usub_words_vliw_inner3);
	return c >> BN_NWORDS;
}

#if defined(DEEP_VLIW)
#define bn_uadd_words bn_uadd_words_vliw
#define bn_uadd_words_c bn_uadd_words_c_vliw
#define bn_usub_words bn_usub_words_vliw
#define bn_usub_words_c bn_usub_words_c_vliw
#else
#define bn_uadd_words bn_uadd_words_seq
#define bn_uadd_words_c bn_uadd_words_c_seq
#define bn_usub_words bn_usub_words_seq
#define bn_usub_words_c bn_usub_words_c_seq
#endif

#define bn_uadd(r, a, b) bn_uadd_words((r)->d, (a)->d, (b)->d)
#define bn_uadd_c(r, a, b) bn_uadd_words_c((r)->d, (a)->d, b)
#define bn_usub(r, a, b) bn_usub_words((r)->d, (a)->d, (b)->d)
#define bn_usub_c(r, a, b) bn_usub_words_c((r)->d, (a)->d, b)

/*
 * Modular add/sub
 */

void
bn_mod_add(bignum *r, bignum *a, bignum *b)
{
	if (bn_uadd(r, a, b) ||
	    (bn_ucmp_ge_c(r, modulus)))
		bn_usub_c(r, r, modulus);
}

void
bn_mod_sub(bignum *r, bignum *a, bignum *b)
{
	if (bn_usub(r, a, b))
		bn_uadd_c(r, r, modulus);
}

void
bn_mod_lshift1(bignum *bn)
{
	bn_word c = (bn->d[BN_NWORDS-1] & 0x80000000);
	bn_lshift1(bn);
	if (c || (bn_ucmp_ge_c(bn, modulus)))
		bn_usub_c(bn, bn, modulus);
}

/*
 * Montgomery multiplication
 *
 * This includes normal multiplication of two "Montgomeryized"
 * bignums, and bn_from_mont for de-Montgomeryizing a bignum.
 */

#define bn_mul_word(r, a, w, c, p, s) do { \
		r = (a * w) + c;	   \
		p = mul_hi(a, w);	   \
		c = (r < c) ? p + 1 : p;   \
	} while (0)

#define bn_mul_add_word(r, a, w, c, p, s) do {	\
		s = r + c;			\
		p = mul_hi(a, w);		\
		r = (a * w) + s;		\
		c = (s < c) ? p + 1 : p;	\
		if (r < s) c++;			\
	} while (0)
void
bn_mul_mont(bignum *r, bignum *a, bignum *b)
{
	bignum t;
	bn_word tea, teb, c, p, s, m;

#if !defined(VERY_EXPENSIVE_BRANCHES)
	int q;
#endif

	c = 0;
#define bn_mul_mont_inner1(j)					\
		bn_mul_word(t.d[j], a->d[j], b->d[0], c, p, s);
	bn_unroll(bn_mul_mont_inner1);
	tea = c;
	teb = 0;

	c = 0;
	m = t.d[0] * mont_n0[0];
	bn_mul_add_word(t.d[0], modulus[0], m, c, p, s);
#define bn_mul_mont_inner2(j)						\
		bn_mul_add_word(t.d[j], modulus[j], m, c, p, s);	\
		t.d[j-1] = t.d[j];
	bn_unroll_sf(bn_mul_mont_inner2);
	t.d[BN_NWORDS-1] = tea + c;
	tea = teb + ((t.d[BN_NWORDS-1] < c) ? 1 : 0);

#define bn_mul_mont_inner3_1(i, j)					\
		bn_mul_add_word(t.d[j], a->d[j], b->d[i], c, p, s);
#define bn_mul_mont_inner3_2(i, j)					\
		bn_mul_add_word(t.d[j], modulus[j], m, c, p, s);	\
		t.d[j-1] = t.d[j];
#define bn_mul_mont_inner3(i)				 \
	c = 0;						 \
	bn_unroll_arg(bn_mul_mont_inner3_1, i);		 \
	tea += c;					 \
	teb = ((tea < c) ? 1 : 0);			 \
	c = 0;						 \
	m = t.d[0] * mont_n0[0];			 \
	bn_mul_add_word(t.d[0], modulus[0], m, c, p, s); \
	bn_unroll_arg_sf(bn_mul_mont_inner3_2, i);	 \
	t.d[BN_NWORDS-1] = tea + c;			 \
	tea = teb + ((t.d[BN_NWORDS-1] < c) ? 1 : 0);

	/*
	 * The outer loop here is quite long, and we won't unroll it
	 * unless VERY_EXPENSIVE_BRANCHES is set.
	 */
#if defined(VERY_EXPENSIVE_BRANCHES)
	bn_unroll_sf(bn_mul_mont_inner3);
	c = tea | !bn_usub_c(r, &t, modulus);
	if (!c)
		*r = t;

#else
	for (q = 1; q < BN_NWORDS; q++) {
		bn_mul_mont_inner3(q);
	}
	c = tea || (t.d[BN_NWORDS-1] >= modulus[BN_NWORDS-1]);
	if (c) {
		c = tea | !bn_usub_c(r, &t, modulus);
		if (c)
			return;
	}
	*r = t;
#endif
}

void
bn_from_mont(bignum *rb, bignum *b)
{
#define WORKSIZE ((2*BN_NWORDS) + 1)
	bn_word r[WORKSIZE];
	bn_word m, c, p, s;
#if defined(PRAGMA_UNROLL)
	int i;
#endif

	/* Copy the input to the working area */
	/* Zero the upper words */
#define bn_from_mont_inner1(i)			\
	r[i] = b->d[i];
#define bn_from_mont_inner2(i)			\
	r[BN_NWORDS+i] = 0;

	bn_unroll(bn_from_mont_inner1);
	bn_unroll(bn_from_mont_inner2);
	r[WORKSIZE-1] = 0;

	/* Multiply (long) by modulus */
#define bn_from_mont_inner3_1(i, j) \
	bn_mul_add_word(r[i+j], modulus[j], m, c, p, s);

#if !defined(VERY_EXPENSIVE_BRANCHES)
#define bn_from_mont_inner3_2(i)		\
	if (r[BN_NWORDS + i] < c)		\
		r[BN_NWORDS + i + 1] += 1;
#else
#define bn_from_mont_inner3_2(i)				\
	r[BN_NWORDS + i + 1] += (r[BN_NWORDS + i] < c) ? 1 : 0;
#endif

#define bn_from_mont_inner3(i)			 \
	m = r[i] * mont_n0[0];			 \
	c = 0;					 \
	bn_unroll_arg(bn_from_mont_inner3_1, i); \
	r[BN_NWORDS + i] += c;			 \
	bn_from_mont_inner3_2(i)

	/*
	 * The outer loop here is not very long, so we will unroll
	 * it by default.  However, it's just complicated enough to
	 * cause NVIDIA's compiler to take unreasonably long to compile
	 * it, unless we use pragma unroll.
	 */
#if !defined(PRAGMA_UNROLL)
	bn_iter(bn_from_mont_inner3);
#else
#pragma unroll 8
	for (i = 0; i < BN_NWORDS; i++) { bn_from_mont_inner3(i) }
#endif

	/*
	 * Make sure the result is less than the modulus.
	 * Subtracting is not much more expensive than compare, so
	 * subtract always and assign based on the carry out value.
	 */
	c = bn_usub_words_c(rb->d, &r[BN_NWORDS], modulus);
	if (c) {
#define bn_from_mont_inner4(i)				\
			rb->d[i] = r[BN_NWORDS + i];
		bn_unroll(bn_from_mont_inner4);
	}
}

/*
 * Modular inversion
 */

void
bn_mod_inverse(bignum *r, bignum *n)
{
	bignum a, b, x, y;
	int shift;
	bn_word xc, yc;
	for (shift = 0; shift < BN_NWORDS; shift++) {
		a.d[shift] = modulus[shift];
		x.d[shift] = 0;
		y.d[shift] = 0;
	}
	b = *n;
	x.d[0] = 1;
	xc = 0;
	yc = 0;
	while (!bn_is_zero(b)) {
		shift = 0;
		while (!bn_is_odd(b)) {
			if (bn_is_odd(x))
				xc += bn_uadd_c(&x, &x, modulus);
			bn_rshift1_2(&x, &b);
			x.d[7] |= (xc << 31);
			xc >>= 1;
		}

		while (!bn_is_odd(a)) {
			if (bn_is_odd(y))
				yc += bn_uadd_c(&y, &y, modulus);
			bn_rshift1_2(&y, &a);
			y.d[7] |= (yc << 31);
			yc >>= 1;
		}

		if (bn_ucmp_ge(&b, &a)) {
			xc += yc + bn_uadd(&x, &x, &y);
			bn_usub(&b, &b, &a);
		} else {
			yc += xc + bn_uadd(&y, &y, &x);
			bn_usub(&a, &a, &b);
		}
	}

	if (!bn_is_one(a)) {
		/* no modular inverse */
		*r = bn_zero;
	} else {
		/* Compute y % m as cheaply as possible */
		while (yc < 0x80000000)
			yc -= bn_usub_c(&y, &y, modulus);
		bn_neg(&y);
		*r = y;
	}
}

/*
 * HASH FUNCTIONS
 *
 * BYTE ORDER NOTE: None of the hash functions below deal with byte
 * order.  The caller is expected to be aware of this when it stuffs
 * data into in the native integer.
 *
 * NOTE #2: Endianness of the OpenCL device makes no difference here.
 */

#define hash256_unroll(a) unroll_8(a)
#define hash160_unroll(a) unroll_5(a)
#define hash256_iter(a) iter_8(a)
#define hash160_iter(a) iter_5(a)

/*
 * SHA-2 256
 *
 * CAUTION: Input buffer will be overwritten/mangled.
 * Data expected in big-endian format.
 * This implementation is designed for space efficiency more than
 * raw speed.
 */

__constant uint sha2_init[8] = {
	0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
	0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};

__constant uint sha2_k[64] = {
	0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
	0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
	0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
	0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
	0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
	0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
	0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
	0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
	0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
	0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
	0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
	0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
	0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
	0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
	0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
	0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};

void
sha2_256_init(uint *out)
{
#define sha2_256_init_inner_1(i) \
	out[i] = sha2_init[i];

	hash256_unroll(sha2_256_init_inner_1);
}

/* The state variable remapping is really contorted */
#define sha2_stvar(vals, i, v) vals[(64+v-i) % 8]
#define sha2_s0(a) (rotate(a, 30U) ^ rotate(a, 19U) ^ rotate(a, 10U))
#define sha2_s1(a) (rotate(a, 26U) ^ rotate(a, 21U) ^ rotate(a, 7U))
#if defined(AMD_BFI_INT)
#pragma OPENCL EXTENSION cl_amd_media_ops : enable
#define sha2_ch(a, b, c) amd_bytealign(a, b, c)
#define sha2_ma(a, b, c) amd_bytealign((a^c), b, a)
#else
#define sha2_ch(a, b, c) (c ^ (a & (b ^ c)))
#define sha2_ma(a, b, c) ((a & c) | (b & (a | c)))
#endif

void
sha2_256_block(uint *out, uint *in)
{
	uint state[8], t1, t2;
#if defined(PRAGMA_UNROLL)
	int i;
#endif

#define sha2_256_block_inner_1(i) \
	state[i] = out[i];
	hash256_unroll(sha2_256_block_inner_1);

#define sha2_256_block_inner_2(i) \
	if (i >= 16) {							\
		t1 = in[(i + 1) % 16];					\
		t2 = in[(i + 14) % 16];					\
		in[i % 16] += (in[(i + 9) % 16] +			\
		       (rotate(t1, 25U) ^ rotate(t1, 14U) ^ (t1 >> 3)) + \
		       (rotate(t2, 15U) ^ rotate(t2, 13U) ^ (t2 >> 10))); \
	}								\
	t1 = (sha2_stvar(state, i, 7) +					\
	      sha2_s1(sha2_stvar(state, i, 4)) +			\
	      sha2_ch(sha2_stvar(state, i, 4),				\
		      sha2_stvar(state, i, 5),				\
		      sha2_stvar(state, i, 6)) +			\
	      sha2_k[i] +						\
	      in[i % 16]);						\
	t2 = (sha2_s0(sha2_stvar(state, i, 0)) +			\
	      sha2_ma(sha2_stvar(state, i, 0),				\
		      sha2_stvar(state, i, 1),				\
		      sha2_stvar(state, i, 2)));			\
	sha2_stvar(state, i, 3) += t1;					\
	sha2_stvar(state, i, 7) = t1 + t2;				\

#if !defined(PRAGMA_UNROLL)
	iter_64(sha2_256_block_inner_2);
#else
#pragma unroll 64
	for (i = 0; i < 64; i++) { sha2_256_block_inner_2(i) }
#endif

#define sha2_256_block_inner_3(i) \
	out[i] += state[i];

	hash256_unroll(sha2_256_block_inner_3);
}

/*
 * RIPEMD160
 *
 * Data expected in little-endian format.
 */

__constant uint ripemd160_iv[] = {
	0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 };
__constant uint ripemd160_k[] = {
	0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E };
__constant uint ripemd160_kp[] = {
	0x50A28BE6, 0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000 };
__constant uchar ripemd160_ws[] = {
	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
	7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
	3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
	1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
	4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13,
};
__constant uchar ripemd160_wsp[] = {
	5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
	6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
	15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
	8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
	12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
};
__constant uchar ripemd160_rl[] = {
	11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
	7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
	11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
	11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
	9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6,
};
__constant uchar ripemd160_rlp[] = {
	8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
	9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
	9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
	15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
	8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
};

#define ripemd160_val(v, i, n) (v)[(80+(n)-(i)) % 5]
#define ripemd160_valp(v, i, n) (v)[5 + ((80+(n)-(i)) % 5)]
#if defined(AMD_BFI_INT)
#define ripemd160_f0(x, y, z) (x ^ y ^ z)
#define ripemd160_f1(x, y, z) amd_bytealign(x, y, z)
#define ripemd160_f2(x, y, z) (z ^ (x | ~y))
#define ripemd160_f3(x, y, z) amd_bytealign(z, x, y)
#define ripemd160_f4(x, y, z) (x ^ (y | ~z))
#else
#define ripemd160_f0(x, y, z) (x ^ y ^ z)
#define ripemd160_f1(x, y, z) ((x & y) | (~x & z))
#define ripemd160_f2(x, y, z) (z ^ (x | ~y))
#define ripemd160_f3(x, y, z) ((x & z) | (y & ~z))
#define ripemd160_f4(x, y, z) (x ^ (y | ~z))
#endif
#define ripemd160_round(i, in, vals, f, fp, t) do {			\
		ripemd160_val(vals, i, 0) =				\
			rotate(ripemd160_val(vals, i, 0) +		\
			       f(ripemd160_val(vals, i, 1),		\
				 ripemd160_val(vals, i, 2),		\
				 ripemd160_val(vals, i, 3)) +		\
			       in[ripemd160_ws[i]] +			\
			       ripemd160_k[i / 16],			\
			       (uint)ripemd160_rl[i]) +			\
			ripemd160_val(vals, i, 4);			\
		ripemd160_val(vals, i, 2) =				\
			rotate(ripemd160_val(vals, i, 2), 10U);		\
		ripemd160_valp(vals, i, 0) =				\
			rotate(ripemd160_valp(vals, i, 0) +		\
			       fp(ripemd160_valp(vals, i, 1),		\
				  ripemd160_valp(vals, i, 2),		\
				  ripemd160_valp(vals, i, 3)) +		\
			       in[ripemd160_wsp[i]] +			\
			       ripemd160_kp[i / 16],			\
			       (uint)ripemd160_rlp[i]) +		\
			ripemd160_valp(vals, i, 4);			\
		ripemd160_valp(vals, i, 2) =				\
			rotate(ripemd160_valp(vals, i, 2), 10U);	\
	} while (0)

void
ripemd160_init(uint *out)
{
#define ripemd160_init_inner_1(i) \
	out[i] = ripemd160_iv[i];

	hash160_unroll(ripemd160_init_inner_1);
}

void
ripemd160_block(uint *out, uint *in)
{
	uint vals[10], t;
#if defined(PRAGMA_UNROLL)
	int i;
#endif

#define ripemd160_block_inner_1(i) \
	vals[i] = vals[i + 5] = out[i];

	hash160_unroll(ripemd160_block_inner_1);

#define ripemd160_block_inner_p0(i)		\
	ripemd160_round(i, in, vals, \
			ripemd160_f0, ripemd160_f4, t);
#define ripemd160_block_inner_p1(i)		\
	ripemd160_round((16 + i), in, vals,		\
			ripemd160_f1, ripemd160_f3, t);
#define ripemd160_block_inner_p2(i)		\
	ripemd160_round((32 + i), in, vals,		\
			ripemd160_f2, ripemd160_f2, t);
#define ripemd160_block_inner_p3(i)		\
	ripemd160_round((48 + i), in, vals,		\
			ripemd160_f3, ripemd160_f1, t);
#define ripemd160_block_inner_p4(i)		\
	ripemd160_round((64 + i), in, vals,		\
			ripemd160_f4, ripemd160_f0, t);

#if !defined(PRAGMA_UNROLL)
	iter_16(ripemd160_block_inner_p0);
	iter_16(ripemd160_block_inner_p1);
	iter_16(ripemd160_block_inner_p2);
	iter_16(ripemd160_block_inner_p3);
	iter_16(ripemd160_block_inner_p4);
#else
#pragma unroll 16
	for (i = 0; i < 16; i++) { ripemd160_block_inner_p0(i); }
#pragma unroll 16
	for (i = 0; i < 16; i++) { ripemd160_block_inner_p1(i); }
#pragma unroll 16
	for (i = 0; i < 16; i++) { ripemd160_block_inner_p2(i); }
#pragma unroll 16
	for (i = 0; i < 16; i++) { ripemd160_block_inner_p3(i); }
#pragma unroll 16
	for (i = 0; i < 16; i++) { ripemd160_block_inner_p4(i); }
#endif

	t = out[1] + vals[2] + vals[8];
	out[1] = out[2] + vals[3] + vals[9];
	out[2] = out[3] + vals[4] + vals[5];
	out[3] = out[4] + vals[0] + vals[6];
	out[4] = out[0] + vals[1] + vals[7];
	out[0] = t;
}

#ifdef TEST_KERNELS
/*
 * Test kernels
 */

/* Montgomery multiplication test kernel */
__kernel void
test_mul_mont(__global bignum *products_out, __global bignum *nums_in)
{
	bignum a, b, c;
	int o;
	o = get_global_id(0);
	nums_in += (2*o);

	a = nums_in[0];
	b = nums_in[1];
	bn_mul_mont(&c, &a, &b);
	products_out[o] = c;
}

/* modular inversion test kernel */
__kernel void
test_mod_inverse(__global bignum *inv_out, __global bignum *nums_in,
		 int count)
{
	bignum x, xp;
	int i, o;
	o = get_global_id(0) * count;
	for (i = 0; i < count; i++) {
		x = nums_in[o];
		bn_mod_inverse(&xp, &x);
		inv_out[o++] = xp;
	}
}
#endif  /* TEST_KERNELS */

#define ACCESS_BUNDLE 1024
#define ACCESS_STRIDE (ACCESS_BUNDLE/BN_NWORDS)

__kernel void
ec_add_grid(__global bn_word *points_out, __global bn_word *z_heap,
	    __global bn_word *row_in, __global bignum *col_in)
{
	bignum rx, ry;
	bignum x1, y1, a, b, c, d, e, z;
	bn_word cy;
	int i, cell, start;

	/* Load the row increment point */
	i = 2 * get_global_id(1);
	rx = col_in[i];
	ry = col_in[i+1];

	cell = get_global_id(0);
	start = ((((2 * cell) / ACCESS_STRIDE) * ACCESS_BUNDLE) +
		 (cell % (ACCESS_STRIDE/2)));

#define ec_add_grid_inner_1(i) \
	x1.d[i] = row_in[start + (i*ACCESS_STRIDE)];

	bn_unroll(ec_add_grid_inner_1);
	start += (ACCESS_STRIDE/2);

#define ec_add_grid_inner_2(i) \
	y1.d[i] = row_in[start + (i*ACCESS_STRIDE)];

	bn_unroll(ec_add_grid_inner_2);

	bn_mod_sub(&z, &x1, &rx);

	cell += (get_global_id(1) * get_global_size(0));
	start = (((cell / ACCESS_STRIDE) * ACCESS_BUNDLE) +
		 (cell % ACCESS_STRIDE));

#define ec_add_grid_inner_3(i) \
	z_heap[start + (i*ACCESS_STRIDE)] = z.d[i];

	bn_unroll(ec_add_grid_inner_3);

	bn_mod_sub(&b, &y1, &ry);
	bn_mod_add(&c, &x1, &rx);
	bn_mod_add(&d, &y1, &ry);
	bn_mul_mont(&y1, &b, &b);
	bn_mul_mont(&x1, &z, &z);
	bn_mul_mont(&e, &c, &x1);
	bn_mod_sub(&y1, &y1, &e);

	/*
	 * This disgusting code caters to the global memory unit on
	 * various GPUs, by giving it a nice contiguous patch to write
	 * per warp/wavefront.
	 */
	start = ((((2 * cell) / ACCESS_STRIDE) * ACCESS_BUNDLE) +
		 (cell % (ACCESS_STRIDE/2)));

#define ec_add_grid_inner_4(i) \
	points_out[start + (i*ACCESS_STRIDE)] = y1.d[i];

	bn_unroll(ec_add_grid_inner_4);

	bn_mod_lshift1(&y1);
	bn_mod_sub(&y1, &e, &y1);
	bn_mul_mont(&y1, &y1, &b);
	bn_mul_mont(&a, &x1, &z);
	bn_mul_mont(&c, &d, &a);
	bn_mod_sub(&y1, &y1, &c);
	cy = 0;
	if (bn_is_odd(y1))
		cy = bn_uadd_c(&y1, &y1, modulus);
	bn_rshift1(&y1);
	y1.d[BN_NWORDS-1] |= (cy ? 0x80000000 : 0);

	start += (ACCESS_STRIDE/2);

	bn_unroll(ec_add_grid_inner_4);
}

__kernel void
heap_invert(__global bn_word *z_heap, int batch)
{
	bignum a, b, c, z;
	int i, off, lcell, hcell, start;

#define heap_invert_inner_load_a(j)				\
		a.d[j] = z_heap[start + j*ACCESS_STRIDE];
#define heap_invert_inner_load_b(j)				\
		b.d[j] = z_heap[start + j*ACCESS_STRIDE];
#define heap_invert_inner_load_z(j)				\
		z.d[j] = z_heap[start + j*ACCESS_STRIDE];
#define heap_invert_inner_store_z(j)				\
		z_heap[start + j*ACCESS_STRIDE] = z.d[j];
#define heap_invert_inner_store_c(j)				\
		z_heap[start + j*ACCESS_STRIDE] = c.d[j];

	off = get_global_size(0);
	lcell = get_global_id(0);
	hcell = (off * batch) + lcell;
	for (i = 0; i < (batch-1); i++) {

		start = (((lcell / ACCESS_STRIDE) * ACCESS_BUNDLE) +
			 (lcell % ACCESS_STRIDE));

		bn_unroll(heap_invert_inner_load_a);

		lcell += off;
		start = (((lcell / ACCESS_STRIDE) * ACCESS_BUNDLE) +
			 (lcell % ACCESS_STRIDE));

		bn_unroll(heap_invert_inner_load_b);

		bn_mul_mont(&z, &a, &b);

		start = (((hcell / ACCESS_STRIDE) * ACCESS_BUNDLE) +
			 (hcell % ACCESS_STRIDE));

		bn_unroll(heap_invert_inner_store_z);

		lcell += off;
		hcell += off;
	}

	/* Invert the root, fix up 1/ZR -> R/Z */
	bn_mod_inverse(&z, &z);

#define heap_invert_inner_1(i)			\
	a.d[i] = mont_rr[i];

	bn_unroll(heap_invert_inner_1);

	bn_mul_mont(&z, &z, &a);
	bn_mul_mont(&z, &z, &a);

	/* Unroll the first iteration to avoid a load/store on the root */
	lcell -= (off << 1);
	hcell -= (off << 1);

	start = (((lcell / ACCESS_STRIDE) * ACCESS_BUNDLE) +
		 (lcell % ACCESS_STRIDE));
	bn_unroll(heap_invert_inner_load_a);

	lcell += off;
	start = (((lcell / ACCESS_STRIDE) * ACCESS_BUNDLE) +
		 (lcell % ACCESS_STRIDE));
	bn_unroll(heap_invert_inner_load_b);

	bn_mul_mont(&c, &a, &z);

	bn_unroll(heap_invert_inner_store_c);

	bn_mul_mont(&c, &b, &z);

	lcell -= off;
	start = (((lcell / ACCESS_STRIDE) * ACCESS_BUNDLE) +
		 (lcell % ACCESS_STRIDE));
	bn_unroll(heap_invert_inner_store_c);

	lcell -= (off << 1);

	for (i = 0; i < (batch-2); i++) {
		start = (((hcell / ACCESS_STRIDE) * ACCESS_BUNDLE) +
			 (hcell % ACCESS_STRIDE));
		bn_unroll(heap_invert_inner_load_z);

		start = (((lcell / ACCESS_STRIDE) * ACCESS_BUNDLE) +
			 (lcell % ACCESS_STRIDE));
		bn_unroll(heap_invert_inner_load_a);

		lcell += off;
		start = (((lcell / ACCESS_STRIDE) * ACCESS_BUNDLE) +
			 (lcell % ACCESS_STRIDE));
		bn_unroll(heap_invert_inner_load_b);

		bn_mul_mont(&c, &a, &z);

		bn_unroll(heap_invert_inner_store_c);

		bn_mul_mont(&c, &b, &z);

		lcell -= off;
		start = (((lcell / ACCESS_STRIDE) * ACCESS_BUNDLE) +
			 (lcell % ACCESS_STRIDE));
		bn_unroll(heap_invert_inner_store_c);

		lcell -= (off << 1);
		hcell -= off;
	}
}

void
hash_ec_point(uint *hash_out, __global bn_word *xy, __global bn_word *zip)
{
	uint hash1[16], hash2[16];
	bignum c, zi, zzi;
	bn_word wh, wl;

	/*
	 * Multiply the coordinates by the inverted Z values.
	 * Stash the coordinates in the hash buffer.
	 * SHA-2 requires big endian, and our intended hash input
	 * is big-endian, so swapping is unnecessary, but
	 * inserting the format byte in front causes a headache.
	 */
#define hash_ec_point_inner_1(i)		\
	zi.d[i] = zip[i*ACCESS_STRIDE];

	bn_unroll(hash_ec_point_inner_1);

	bn_mul_mont(&zzi, &zi, &zi);  /* 1 / Z^2 */

#define hash_ec_point_inner_2(i)		\
	c.d[i] = xy[i*ACCESS_STRIDE];

	bn_unroll(hash_ec_point_inner_2);

	bn_mul_mont(&c, &c, &zzi);  /* X / Z^2 */
	bn_from_mont(&c, &c);

	wh = compressed_address ? 0x00000002 : 0x00000004;  /* POINT_CONVERSION_[UN]COMPRESSED */

#define hash_ec_point_inner_3(i)		\
	wl = wh;				\
	wh = c.d[(BN_NWORDS - 1) - i];		\
	hash1[i] = (wl << 24) | (wh >> 8);

	bn_unroll(hash_ec_point_inner_3);

	bn_mul_mont(&zzi, &zzi, &zi);  /* 1 / Z^3 */

#define hash_ec_point_inner_4(i)				\
	c.d[i] = xy[(ACCESS_STRIDE/2) + i*ACCESS_STRIDE];

	bn_unroll(hash_ec_point_inner_4);

	bn_mul_mont(&c, &c, &zzi);  /* Y / Z^3 */
	bn_from_mont(&c, &c);

	if (!compressed_address) {
		#define hash_ec_point_inner_5(i)			\
			wl = wh;					\
			wh = c.d[(BN_NWORDS - 1) - i];			\
			hash1[BN_NWORDS + i] = (wl << 24) | (wh >> 8);

		bn_unroll(hash_ec_point_inner_5);
	} else {
		if (bn_is_odd(c)) {
			hash1[0] |= 0x01000000; /* 0x03 for odd y */
		}

		/*
		 * Put in the last byte + SHA-2 padding.
		 */
		hash1[8] = wh << 24 | 0x800000;
		hash1[9] = 0;
		hash1[10] = 0;
		hash1[11] = 0;
		hash1[12] = 0;
		hash1[13] = 0;
		hash1[14] = 0;
		hash1[15] = 33 * 8;
	}

	/*
	 * Hash the first 64 bytes of the buffer
	 */
	sha2_256_init(hash2);
	sha2_256_block(hash2, hash1);

	if (!compressed_address) {
		/*
		 * Hash the last byte of the buffer + SHA-2 padding
		 */
		hash1[0] = wh << 24 | 0x800000;
		hash1[1] = 0;
		hash1[2] = 0;
		hash1[3] = 0;
		hash1[4] = 0;
		hash1[5] = 0;
		hash1[6] = 0;
		hash1[7] = 0;
		hash1[8] = 0;
		hash1[9] = 0;
		hash1[10] = 0;
		hash1[11] = 0;
		hash1[12] = 0;
		hash1[13] = 0;
		hash1[14] = 0;
		hash1[15] = 65 * 8;
		sha2_256_block(hash2, hash1);
	}

	/*
	 * Hash the SHA-2 result with RIPEMD160
	 * Unfortunately, SHA-2 outputs big-endian, but
	 * RIPEMD160 expects little-endian.  Need to swap!
	 */

#define hash_ec_point_inner_6(i)		\
	hash2[i] = bswap32(hash2[i]);

	hash256_unroll(hash_ec_point_inner_6);

	hash2[8] = bswap32(0x80000000);
	hash2[9] = 0;
	hash2[10] = 0;
	hash2[11] = 0;
	hash2[12] = 0;
	hash2[13] = 0;
	hash2[14] = 32 * 8;
	hash2[15] = 0;
	ripemd160_init(hash_out);
	ripemd160_block(hash_out, hash2);
}

__kernel void
hash_ec_point_get(__global uint *hashes_out,
		  __global bn_word *points_in, __global bn_word *z_heap)
{
	uint hash[5];
	int i, p, cell, start;

	cell = ((get_global_id(1) * get_global_size(0)) + get_global_id(0));
	start = (((cell / ACCESS_STRIDE) * ACCESS_BUNDLE) +
		 (cell % ACCESS_STRIDE));
	z_heap += start;

	start = ((((2 * cell) / ACCESS_STRIDE) * ACCESS_BUNDLE) +
		 (cell % (ACCESS_STRIDE/2)));
	points_in += start;

	/* Complete the coordinates and hash */
	hash_ec_point(hash, points_in, z_heap);

	p = get_global_size(0);
	i = p * get_global_id(1);
	hashes_out += 5 * (i + get_global_id(0));

	/* Output the hash in proper byte-order */
#define hash_ec_point_get_inner_1(i)		\
	hashes_out[i] = load_le32(hash[i]);

	hash160_unroll(hash_ec_point_get_inner_1);
}

/*
 * Normally this would be one function that compared two hash160s.
 * This one compares a hash160 with an upper and lower bound in one
 * function to work around a problem with AMD's OpenCL compiler.
 */
int
hash160_ucmp_g(uint *a, __global uint *bound)
{
	uint gv;

#define hash160_ucmp_g_inner_1(i) 		\
		gv = load_be32(bound[i]);	\
		if (a[i] < gv) return -1;	\
		if (a[i] > gv) break;

	hash160_iter(hash160_ucmp_g_inner_1);

#define hash160_ucmp_g_inner_2(i)   		\
		gv = load_be32(bound[5+i]);	\
		if (a[i] < gv) return 0;	\
		if (a[i] > gv) return 1;

	hash160_iter(hash160_ucmp_g_inner_2);
	return 0;
}

__kernel void
hash_ec_point_search_prefix(__global uint *found,
			    __global bn_word *points_in,
			    __global bn_word *z_heap,
			    __global uint *target_table, int ntargets)
{
	uint hash[5];
	int i, high, low, p, cell, start;

	cell = ((get_global_id(1) * get_global_size(0)) + get_global_id(0));
	start = (((cell / ACCESS_STRIDE) * ACCESS_BUNDLE) +
		 (cell % ACCESS_STRIDE));
	z_heap += start;

	start = ((((2 * cell) / ACCESS_STRIDE) * ACCESS_BUNDLE) +
		 (cell % (ACCESS_STRIDE/2)));
	points_in += start;

	/* Complete the coordinates and hash */
	hash_ec_point(hash, points_in, z_heap);

	/*
	 * Unconditionally byteswap the hash result, because:
	 * - The byte-level convention of RIPEMD160 is little-endian
	 * - We are comparing it in big-endian order
	 */
#define hash_ec_point_search_prefix_inner_1(i)	\
	hash[i] = bswap32(hash[i]);

	hash160_unroll(hash_ec_point_search_prefix_inner_1);

	/* Binary-search the target table for the hash we just computed */
	for (high = ntargets - 1, low = 0, i = high >> 1;
	     high >= low;
	     i = low + ((high - low) >> 1)) {
		p = hash160_ucmp_g(hash, &target_table[10*i]);
		low = (p > 0) ? (i + 1) : low;
		high = (p < 0) ? (i - 1) : high;
		if (p == 0) {
			/* For debugging purposes, write the hash value */
			found[0] = ((get_global_id(1) * get_global_size(0)) +
				    get_global_id(0));
			found[1] = i;

#define hash_ec_point_search_prefix_inner_2(i)	\
			found[i+2] = load_be32(hash[i]);

			hash160_unroll(hash_ec_point_search_prefix_inner_2);
			high = -1;
		}
	}
}

error: pathspec 'btcdetector/src/main/resources/calc_addrs.cl' did not match any file(s) known to git


Example of a convolution in OpenCL.  Initial version.

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

#undef DEBUG_PRINT

#ifdef DEBUG_PRINT
#  include <stdio.h>
#endif

//
// Simple compute kernel that computes a convolution over an input array
//
__kernel void convolve (
    __global float * idata,
    __global float * odata,
    const unsigned int nxGlobal,
    const unsigned int nyGlobal,
    const unsigned int nPad,
    __local float * ldata_ex)
{
   const unsigned int kx = get_global_id(0);
   const unsigned int ky = get_global_id(1);
   const unsigned int k  = kx + ky*nxGlobal;

   const unsigned int kxl = get_local_id(0);
   const unsigned int kyl = get_local_id(1);
   const unsigned int kl  = kxl + kyl*(get_local_size(0) + 2*nPad);

   const unsigned int klex = (kxl + nPad) + (kyl + nPad)*(get_local_size(0) + 2*nPad);

   // copy extended region
   //
   // WARNING - this only works if 2*nPad <= NXL, 2*nPad <= NYL
   //
   if (k < nxGlobal*nyGlobal) {
      // copy NXL portion of each row
      ldata_ex[kxl + kyl*(get_local_size(0) + 2*nPad)]
                   = idata[kx + ky*(nxGlobal + 2*nPad)];
      // copy leftover section on the right of each row
      if (kxl < 2*nPad) {
         ldata_ex[kxl + get_local_size(0) + kyl*(get_local_size(0) + 2*nPad)]
                   = idata[kx + get_local_size(0) + ky*(nxGlobal + 2*nPad)];
      }
      // copy leftover section on the bottom
      if (kyl < 2*nPad) {
         ldata_ex[kxl + (kyl + get_local_size(1))*(get_local_size(0) + 2*nPad)]
                   = idata[kx + (ky + get_local_size(1))*(nxGlobal + 2*nPad)];
         // copy leftover section on the right
         if (kxl < 2*nPad) {
            ldata_ex[kxl + get_local_size(0) + (kyl + get_local_size(1))*(get_local_size(0) + 2*nPad)]
                   = idata[kx + get_local_size(0) + (ky + get_local_size(1))*(nxGlobal + 2*nPad)];
         }
      }
   }

   barrier(CLK_LOCAL_MEM_FENCE);

   // copy local block back to global memory
   //
   //if (k < nxGlobal*nyGlobal) {
   //   odata[k] = (          ldata_ex[klex-(get_local_size(0)+2*nPad)]
   //                + ldata_ex[klex-1] + ldata_ex[klex] + ldata_ex[klex+1]
   //                +        ldata_ex[klex+(get_local_size(0)+2*nPad)]       ) / 5.0f;
   //}
   if (k < nxGlobal*nyGlobal) {
      float sum = 0.0f;
      const int sy = get_local_size(0) + 2*nPad;

      for (int i = 0; i < 3; i++) {
         int offset = (i-1)*sy;
         sum += 1.1f*ldata_ex[klex+offset-1] + 2.1f*ldata_ex[klex+offset] + 3.1f*ldata_ex[klex+offset+1];
      }

      odata[k] = sum;
   }
}

error: pathspec 'src/arch/opencl/convolve.cl' did not match any file(s) known to git


writes must be in image borders (prima part)

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/mazhe/ClGaussianPyramid.git/'


Bugfix to spike() in Retina_update_state.cl: stimFactor already includes multiplication by dt, so probSpike shouldn't also multiply by dt.

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

#include "Retina_params.h"
#include "cl_random.hcl"

#ifndef PI
#  define PI 3.1415926535897932
#endif

#ifndef PV_USE_OPENCL

#  include <math.h>
#  define EXP  expf
#  define COS  cosf
#  define MOD fmod
#  define CL_KERNEL
#  define CL_MEM_GLOBAL
#  define CL_MEM_CONST
#  define CL_MEM_LOCAL

#else

#  define EXP exp
#  define COS  __cosf
#  define FMOD __fmodf
#  define CL_KERNEL     __kernel
#  define CL_MEM_GLOBAL __global
#  define CL_MEM_CONST    __constant
#  define CL_MEM_LOCAL  __local
#  include "conversions.hcl"
#  define CHANNEL_EXC   0
#  define CHANNEL_INH   1
#  define CHANNEL_INHB  2
#  define CHANNEL_GAP   3

#endif /* PV_USE_OPENCL */

/*
 * Spiking method for Retina
 * Returns 1 if an event should occur, 0 otherwise. This is a stochastic model.
 *
 * REMARKS:
 *      - During ABS_REFRACTORY_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_REFRACTORY_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 milliseconds
 *      - 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
float calcBurstStatus(double timed, CL_MEM_CONST Retina_params * params) {
   float burstStatus;
   if (params->burstDuration <= 0 || params->burstFreq == 0) {
      // sinAmp = COS( 2*PI*time * params->burstFreq / 1000. );
      burstStatus = COS( 2*PI*timed * params->burstFreq / 1000. );
   }
   else {
      burstStatus = MOD(timed, 1000. / params->burstFreq);
      burstStatus = burstStatus < params->burstDuration;
   }
   burstStatus *= (int) ( (timed >= params->beginStim) && (timed < params->endStim) );
   return burstStatus;
}

static inline
int spike(float timed, float dt,
          float prev, float stimFactor, uint4 * rnd_state, float burst_status, CL_MEM_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 refractory period
   //
   if ((timed - prev) < params->abs_refractory_period) {
      return 0;
   }
   else {
      float delta = timed - prev - params->abs_refractory_period;
      float refract = 1.0f - EXP(-delta/params->refractory_period);
      refract = (refract < 0) ? 0 : refract;
      probBase *= refract;
      probStim *= refract;
   }

   // burstStatus = calcBurstStatus(time, params);
//   if (params->burstDuration <= 0 || params->burstFreq == 0) {
//      // sinAmp = COS( 2*PI*time * params->burstFreq / 1000. );
//      burstStatus = 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
//   }
   probSpike += probStim * burst_status;  // negative prob is OK

   // probSpike *= dt; // conversion to expected number of spikes in dt now takes place in setRetinaParams

   *rnd_state = cl_random_get(*rnd_state);
   int spike_flag = (cl_random_prob(*rnd_state) < probSpike);
   // int spike_flag = (pv_random_prob() < probSpike);
   return spike_flag;
}

//
// update the state of a retinal layer (spiking)
//
//    assume called with 1D kernel
//
CL_KERNEL
void Retina_spiking_update_state (
    const int numNeurons,
    const double timed,
    const double dt,

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

    CL_MEM_CONST Retina_params * params,
    CL_MEM_GLOBAL uint4 * rnd,
    CL_MEM_GLOBAL float * GSynHead,
//    CL_MEM_GLOBAL float * phiExc,
//    CL_MEM_GLOBAL float * phiInh,
    CL_MEM_GLOBAL float * activity,
    CL_MEM_GLOBAL float * prevTime)
{
   int k;
   float burst_status = calcBurstStatus(timed, params);
#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];
   CL_MEM_GLOBAL float * phiExc = &GSynHead[CHANNEL_EXC*numNeurons];
   CL_MEM_GLOBAL float * phiInh = &GSynHead[CHANNEL_INH*numNeurons];
   float l_phiExc = phiExc[k];
   float l_phiInh = phiInh[k];
   float l_prev   = prevTime[kex];
   float l_activ;

   l_activ = (float) spike(timed, dt, l_prev, (l_phiExc - l_phiInh), &l_rnd, burst_status, params);
   l_prev  = (l_activ > 0.0f) ? timed : l_prev;

   l_phiExc = 0.0f;
   l_phiInh = 0.0f;

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

#ifndef PV_USE_OPENCL
   }
#endif

}

//
// update the state of a retinal layer (non-spiking)
//
//    assume called with 1D kernel
//
CL_KERNEL
void Retina_nonspiking_update_state (
    const int numNeurons,
    const double timed,
    const double dt,

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

    CL_MEM_CONST Retina_params * params,
    CL_MEM_GLOBAL float * GSynHead,
//    CL_MEM_GLOBAL float * phiExc,
//    CL_MEM_GLOBAL float * phiInh,
    CL_MEM_GLOBAL float * activity)
{
   int k;
   float burstStatus = calcBurstStatus(timed, params);
#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
   //
   CL_MEM_GLOBAL float * phiExc = &GSynHead[CHANNEL_EXC*numNeurons];
   CL_MEM_GLOBAL float * phiInh = &GSynHead[CHANNEL_INH*numNeurons];
   float l_phiExc = phiExc[k];
   float l_phiInh = phiInh[k];
   float l_activ;

   // adding base prob should not change default behavior
   l_activ = burstStatus * params->probStim*(l_phiExc - l_phiInh) + params->probBase;
//   if (l_activ != 0.0f && burstStatus != 1.0f)
//       l_activ *= burstStatus;

   l_phiExc = 0.0f;
   l_phiInh = 0.0f;

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

#ifndef PV_USE_OPENCL
   }
#endif

}

#include "Retina_params.h"
#include "cl_random.hcl"

#ifndef PI
#  define PI 3.1415926535897932
#endif

#ifndef PV_USE_OPENCL

#  include <math.h>
#  define EXP  expf
#  define COS  cosf
#  define MOD fmod
#  define CL_KERNEL
#  define CL_MEM_GLOBAL
#  define CL_MEM_CONST
#  define CL_MEM_LOCAL

#else

#  define EXP exp
#  define COS  __cosf
#  define FMOD __fmodf
#  define CL_KERNEL     __kernel
#  define CL_MEM_GLOBAL __global
#  define CL_MEM_CONST    __constant
#  define CL_MEM_LOCAL  __local
#  include "conversions.hcl"
#  define CHANNEL_EXC   0
#  define CHANNEL_INH   1
#  define CHANNEL_INHB  2
#  define CHANNEL_GAP   3

#endif /* PV_USE_OPENCL */

/*
 * Spiking method for Retina
 * Returns 1 if an event should occur, 0 otherwise. This is a stochastic model.
 *
 * REMARKS:
 *      - During ABS_REFRACTORY_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_REFRACTORY_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 milliseconds
 *      - 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
float calcBurstStatus(double timed, CL_MEM_CONST Retina_params * params) {
   float burstStatus;
   if (params->burstDuration <= 0 || params->burstFreq == 0) {
      // sinAmp = COS( 2*PI*time * params->burstFreq / 1000. );
      burstStatus = COS( 2*PI*timed * params->burstFreq / 1000. );
   }
   else {
      burstStatus = MOD(timed, 1000. / params->burstFreq);
      burstStatus = burstStatus < params->burstDuration;
   }
   burstStatus *= (int) ( (timed >= params->beginStim) && (timed < params->endStim) );
   return burstStatus;
}

static inline
int spike(float timed, float dt,
          float prev, float stimFactor, uint4 * rnd_state, float burst_status, CL_MEM_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 refractory period
   //
   if ((timed - prev) < params->abs_refractory_period) {
      return 0;
   }
   else {
      float delta = timed - prev - params->abs_refractory_period;
      float refract = 1.0f - EXP(-delta/params->refractory_period);
      refract = (refract < 0) ? 0 : refract;
      probBase *= refract;
      probStim *= refract;
   }

   // burstStatus = calcBurstStatus(time, params);
//   if (params->burstDuration <= 0 || params->burstFreq == 0) {
//      // sinAmp = COS( 2*PI*time * params->burstFreq / 1000. );
//      burstStatus = 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
//   }
   probSpike += probStim * burst_status;  // negative prob is OK

   probSpike *= dt; // convert rate from number of spikes per millisecond to number of spikes in dt.

   *rnd_state = cl_random_get(*rnd_state);
   int spike_flag = (cl_random_prob(*rnd_state) < probSpike);
   // int spike_flag = (pv_random_prob() < probSpike);
   return spike_flag;
}

//
// update the state of a retinal layer (spiking)
//
//    assume called with 1D kernel
//
CL_KERNEL
void Retina_spiking_update_state (
    const int numNeurons,
    const double timed,
    const double dt,

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

    CL_MEM_CONST Retina_params * params,
    CL_MEM_GLOBAL uint4 * rnd,
    CL_MEM_GLOBAL float * GSynHead,
//    CL_MEM_GLOBAL float * phiExc,
//    CL_MEM_GLOBAL float * phiInh,
    CL_MEM_GLOBAL float * activity,
    CL_MEM_GLOBAL float * prevTime)
{
   int k;
   float burst_status = calcBurstStatus(timed, params);
#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];
   CL_MEM_GLOBAL float * phiExc = &GSynHead[CHANNEL_EXC*numNeurons];
   CL_MEM_GLOBAL float * phiInh = &GSynHead[CHANNEL_INH*numNeurons];
   float l_phiExc = phiExc[k];
   float l_phiInh = phiInh[k];
   float l_prev   = prevTime[kex];
   float l_activ;

   l_activ = (float) spike(timed, dt, l_prev, (l_phiExc - l_phiInh), &l_rnd, burst_status, params);
   l_prev  = (l_activ > 0.0f) ? timed : l_prev;

   l_phiExc = 0.0f;
   l_phiInh = 0.0f;

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

#ifndef PV_USE_OPENCL
   }
#endif

}

//
// update the state of a retinal layer (non-spiking)
//
//    assume called with 1D kernel
//
CL_KERNEL
void Retina_nonspiking_update_state (
    const int numNeurons,
    const double timed,
    const double dt,

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

    CL_MEM_CONST Retina_params * params,
    CL_MEM_GLOBAL float * GSynHead,
//    CL_MEM_GLOBAL float * phiExc,
//    CL_MEM_GLOBAL float * phiInh,
    CL_MEM_GLOBAL float * activity)
{
   int k;
   float burstStatus = calcBurstStatus(timed, params);
#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
   //
   CL_MEM_GLOBAL float * phiExc = &GSynHead[CHANNEL_EXC*numNeurons];
   CL_MEM_GLOBAL float * phiInh = &GSynHead[CHANNEL_INH*numNeurons];
   float l_phiExc = phiExc[k];
   float l_phiInh = phiInh[k];
   float l_activ;

   // adding base prob should not change default behavior
   l_activ = burstStatus * params->probStim*(l_phiExc - l_phiInh) + params->probBase;
//   if (l_activ != 0.0f && burstStatus != 1.0f)
//       l_activ *= burstStatus;

   l_phiExc = 0.0f;
   l_phiInh = 0.0f;

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

#ifndef PV_USE_OPENCL
   }
#endif

}