Deleting stale commented-out code

Deleting stale commented-out code

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

#include "LIF_params.h"
#include "cl_random.hcl"

#ifndef PV_USE_OPENCL
#  include <math.h>
#  define EXP expf
#  define CL_KERNEL
#  define CL_MEM_GLOBAL
#  define CL_MEM_CONST
#  define CL_MEM_LOCAL
#else  /* compiling with OpenCL */
#  define EXP exp
#  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

//#undef USE_CLRANDOM
#ifndef USE_CLRANDOM
#  include "../utils/pv_random.h"
#endif

inline
float LIFGap_Vmem_derivative(
      const float Vmem,
      const float G_E,
      const float G_I,
      const float G_IB,
      const float G_Gap,
      const float V_E,
      const float V_I,
      const float V_IB,
      const float sum_gap,
      const float Vrest,
      const float tau) {
   float totalconductance = 1.0 + G_E + G_I + G_IB + sum_gap;
   float Vmeminf = (Vrest + V_E*G_E + V_I*G_I + V_IB*G_IB + G_Gap)/totalconductance;
   return totalconductance*(Vmeminf-Vmem)/tau;
}

//
// update the state of a LCALIF layer (spiking)
//
//    assume called with 1D kernel
//
// LCALIF_update_state_beginning uses a Heun scheme for V, using values of the conductances at both the beginning and end of the timestep.  Spikes in the input are applied at the beginning of the timestep.
//
CL_KERNEL
void LCALIF_update_state(
    const int numNeurons,
    const float time,
    const float dt,

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

    float Vscale,
    float * Vadpt,
    float tauTHR,
    const float targetRateHz,

    pvdata_t * integratedSpikeCount,

    CL_MEM_CONST LIF_params * params,
    CL_MEM_GLOBAL uint4 * rnd,
    CL_MEM_GLOBAL float * V,
    CL_MEM_GLOBAL float * Vth,
    CL_MEM_GLOBAL float * G_E,
    CL_MEM_GLOBAL float * G_I,
    CL_MEM_GLOBAL float * G_IB,
    CL_MEM_GLOBAL float * GSynHead,
//    CL_MEM_GLOBAL float * GSynExc,
//    CL_MEM_GLOBAL float * GSynInh,
//    CL_MEM_GLOBAL float * GSynInhB,
//    CL_MEM_GLOBAL float * GSynGap,
    CL_MEM_GLOBAL float * activity,

    const float sum_gap,
    CL_MEM_GLOBAL float * G_Gap)
{

   // convert target rate from Hz to kHz
   float targetRatekHz = targetRateHz/1000;

   // tau parameters
   const float tauO = 1/targetRatekHz;   //Convert target rate from kHz to ms (tauO)

   const float decayE   = EXP(-dt/params->tauE);
   const float decayI   = EXP(-dt/params->tauI);
   const float decayIB  = EXP(-dt/params->tauIB);
   const float decayVth = EXP(-dt/params->tauVth);
   const float decayO   = EXP(-dt/tauO);

   //Convert dt to seconds
   const float dt_sec = .001 * dt;

#ifndef PV_USE_OPENCL

for (int 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
   //

   // local param variables
   float tau, Vrest, VthRest, Vexc, Vinh, VinhB, deltaVth;

   // const float GMAX = 10.0;

   // local variables
   float l_activ;

   uint4 l_rnd = rnd[k];

   float l_V   = V[k];
   float l_Vth = Vth[k];

   // The correction factors to the conductances are so that if l_GSyn_* is the same every timestep,
   // then the asymptotic value of l_G_* will be l_GSyn_*
   float l_G_E  = G_E[k];
   float l_G_I  = G_I[k];
   float l_G_IB = G_IB[k];
   float l_G_Gap = G_Gap[k];

   CL_MEM_GLOBAL float * GSynExc = &GSynHead[CHANNEL_EXC*numNeurons];
   CL_MEM_GLOBAL float * GSynInh = &GSynHead[CHANNEL_INH*numNeurons];
   CL_MEM_GLOBAL float * GSynInhB = &GSynHead[CHANNEL_INHB*numNeurons];
   CL_MEM_GLOBAL float * GSynGap = &GSynHead[CHANNEL_GAP*numNeurons];
   float l_GSynExc  = GSynExc[k];
   float l_GSynInh  = GSynInh[k];
   float l_GSynInhB = GSynInhB[k];
   float l_GSynGap  = GSynGap[k];

   // define local param variables
   //
   tau        = params->tau;
   Vexc       = params->Vexc;
   Vinh       = params->Vinh;
   VinhB      = params->VinhB;
   Vrest      = params->Vrest;

   VthRest  = params->VthRest;
   deltaVth = params->deltaVth;

   // add noise
   //

#ifdef USE_CLRANDOM
   l_rnd = cl_random_get(l_rnd);
   if (cl_random_prob(l_rnd) < dt_sec*params->noiseFreqE) {
      l_rnd = cl_random_get(l_rnd);
      l_GSynExc = l_GSynExc + params->noiseAmpE*cl_random_prob(l_rnd);
   }

   l_rnd = cl_random_get(l_rnd);
   if (cl_random_prob(l_rnd) < dt_sec*params->noiseFreqI) {
      l_rnd = cl_random_get(l_rnd);
      l_GSynInh = l_GSynInh + params->noiseAmpI*cl_random_prob(l_rnd);
   }

   l_rnd = cl_random_get(l_rnd);
   if (cl_random_prob(l_rnd) < dt_sec*params->noiseFreqIB) {
      l_rnd = cl_random_get(l_rnd);
      l_GSynInhB = l_GSynInhB + params->noiseAmpIB*cl_random_prob(l_rnd);
   }
#else
   if (pv_random_prob() < dt_sec*params->noiseFreqE) {
      l_GSynExc = l_GSynExc + params->noiseAmpE*pv_random_prob();
   }

   if (pv_random_prob() < dt_sec*params->noiseFreqI) {
      l_GSynInh = l_GSynInh + params->noiseAmpI*pv_random_prob();
   }

   if (pv_random_prob() < dt_sec*params->noiseFreqIB) {
      l_GSynInhB = l_GSynInhB + params->noiseAmpIB*pv_random_prob();
   }
#endif

   const float GMAX = 10.0;

   // The portion of code below uses the newer method of calculating l_V.
   float G_E_initial, G_I_initial, G_IB_initial, G_E_final, G_I_final, G_IB_final;
   float dV1, dV2, dV;

   G_E_initial = l_G_E + l_GSynExc;
   G_I_initial = l_G_I + l_GSynInh;
   G_IB_initial = l_G_IB + l_GSynInhB;

   G_E_initial  = (G_E_initial  > GMAX) ? GMAX : G_E_initial;
   G_I_initial  = (G_I_initial  > GMAX) ? GMAX : G_I_initial;
   G_IB_initial = (G_IB_initial > GMAX) ? GMAX : G_IB_initial;

   G_E_final = G_E_initial * decayE;
   G_I_final = G_I_initial * decayI;
   G_IB_final = G_IB_initial * decayIB;

   l_G_Gap = l_GSynGap;

   dV1 = LIFGap_Vmem_derivative(l_V, G_E_initial, G_I_initial, G_IB_initial, l_G_Gap, Vexc, Vinh, VinhB, sum_gap, Vrest, tau);
   dV2 = LIFGap_Vmem_derivative(l_V+dt*dV1, G_E_final, G_I_final, G_IB_final, l_G_Gap, Vexc, Vinh, VinhB, sum_gap, Vrest, tau);
   dV = (dV1+dV2)*0.5;
   l_V = l_V + dt*dV;

   l_G_E = G_E_final;
   l_G_I = G_I_final;
   l_G_IB = G_IB_final;

   //l_Vth updates according to traditional LIF rule in addition to the slow threshold adaptation
   //      See LCA_Equations.pdf in the documentation for a full description of the neuron adaptive firing threshold.

   Vadpt[k] += (dt/tauTHR) * ((integratedSpikeCount[k]/tauO) - targetRatekHz) * (Vscale/targetRatekHz);

   l_Vth = Vadpt[k] + decayVth * (l_Vth - Vadpt[k]);

   bool fired_flag = (l_V > l_Vth);

   l_activ = fired_flag ? 1.0f             : 0.0f;
   l_V     = fired_flag ? Vrest            : l_V;
   l_Vth   = fired_flag ? l_Vth + deltaVth : l_Vth;
   l_G_IB  = fired_flag ? l_G_IB + 1.0f    : l_G_IB;

   //integratedSpikeCount is the trace activity of the neuron, with an exponential decay
   integratedSpikeCount[k] = decayO * (l_activ + integratedSpikeCount[k]);

   //
   // These actions must be done outside of kernel
   //    1. set activity to 0 in boundary (if needed)
   //    2. update active indices
   //

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

   activity[kex] = l_activ;

   V[k]   = l_V;
   Vth[k] = l_Vth;

   G_E[k]  = l_G_E;
   G_I[k]  = l_G_I;
   G_IB[k] = l_G_IB;
   G_Gap[k] = l_G_Gap;

   GSynExc[k]  = 0.0f;
   GSynInh[k]  = 0.0f;
   GSynInhB[k] = 0.0f;
   GSynGap[k]  = 0.0f;

#ifndef PV_USE_OPENCL
   } // loop over k
#endif

}

#include "LIF_params.h"
#include "cl_random.hcl"

#ifndef PV_USE_OPENCL
#  include <math.h>
#  define EXP expf
#  define CL_KERNEL
#  define CL_MEM_GLOBAL
#  define CL_MEM_CONST
#  define CL_MEM_LOCAL
#else  /* compiling with OpenCL */
#  define EXP exp
#  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

//#undef USE_CLRANDOM
#ifndef USE_CLRANDOM
#  include "../utils/pv_random.h"
#endif

inline
float LIFGap_Vmem_derivative(
      const float Vmem,
      const float G_E,
      const float G_I,
      const float G_IB,
      const float G_Gap,
      const float V_E,
      const float V_I,
      const float V_IB,
      const float sum_gap,
      const float Vrest,
      const float tau) {
   float totalconductance = 1.0 + G_E + G_I + G_IB + sum_gap;
   float Vmeminf = (Vrest + V_E*G_E + V_I*G_I + V_IB*G_IB + G_Gap)/totalconductance;
   return totalconductance*(Vmeminf-Vmem)/tau;
}

//
// update the state of a LCALIF layer (spiking)
//
//    assume called with 1D kernel
//
// LCALIF_update_state_beginning uses a Heun scheme for V, using values of the conductances at both the beginning and end of the timestep.  Spikes in the input are applied at the beginning of the timestep.
//
CL_KERNEL
void LCALIF_update_state(
    const int numNeurons,
    const float time,
    const float dt,

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

    float Vscale,
    float * Vadpt,
    float tauTHR,
    const float targetRateHz,

    pvdata_t * integratedSpikeCount,

    CL_MEM_CONST LIF_params * params,
    CL_MEM_GLOBAL uint4 * rnd,
    CL_MEM_GLOBAL float * V,
    CL_MEM_GLOBAL float * Vth,
    CL_MEM_GLOBAL float * G_E,
    CL_MEM_GLOBAL float * G_I,
    CL_MEM_GLOBAL float * G_IB,
    CL_MEM_GLOBAL float * GSynHead,
//    CL_MEM_GLOBAL float * GSynExc,
//    CL_MEM_GLOBAL float * GSynInh,
//    CL_MEM_GLOBAL float * GSynInhB,
//    CL_MEM_GLOBAL float * GSynGap,
    CL_MEM_GLOBAL float * activity,

    const float sum_gap,
    CL_MEM_GLOBAL float * G_Gap)
{

   // convert target rate from Hz to kHz
   float targetRatekHz = targetRateHz/1000;

   // tau parameters
   const float tauO = 1/targetRatekHz;   //Convert target rate from kHz to ms (tauO)

   const float decayE   = EXP(-dt/params->tauE);
   const float decayI   = EXP(-dt/params->tauI);
   const float decayIB  = EXP(-dt/params->tauIB);
   const float decayVth = EXP(-dt/params->tauVth);
   const float decayO   = EXP(-dt/tauO);

   //Convert dt to seconds
   const float dt_sec = .001 * dt;

#ifndef PV_USE_OPENCL

for (int 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
   //

   // local param variables
   float tau, Vrest, VthRest, Vexc, Vinh, VinhB, deltaVth;

   // const float GMAX = 10.0;

   // local variables
   float l_activ;

   uint4 l_rnd = rnd[k];

   float l_V   = V[k];
   float l_Vth = Vth[k];

   // The correction factors to the conductances are so that if l_GSyn_* is the same every timestep,
   // then the asymptotic value of l_G_* will be l_GSyn_*
   float l_G_E  = G_E[k];
   float l_G_I  = G_I[k];
   float l_G_IB = G_IB[k];
   float l_G_Gap = G_Gap[k];

   CL_MEM_GLOBAL float * GSynExc = &GSynHead[CHANNEL_EXC*numNeurons];
   CL_MEM_GLOBAL float * GSynInh = &GSynHead[CHANNEL_INH*numNeurons];
   CL_MEM_GLOBAL float * GSynInhB = &GSynHead[CHANNEL_INHB*numNeurons];
   CL_MEM_GLOBAL float * GSynGap = &GSynHead[CHANNEL_GAP*numNeurons];
   float l_GSynExc  = GSynExc[k];
   float l_GSynInh  = GSynInh[k];
   float l_GSynInhB = GSynInhB[k];
   float l_GSynGap  = GSynGap[k];

   // define local param variables
   //
   tau        = params->tau;
   Vexc       = params->Vexc;
   Vinh       = params->Vinh;
   VinhB      = params->VinhB;
   Vrest      = params->Vrest;

   VthRest  = params->VthRest;
   deltaVth = params->deltaVth;

   // add noise
   //

#ifdef USE_CLRANDOM
   l_rnd = cl_random_get(l_rnd);
   if (cl_random_prob(l_rnd) < dt_sec*params->noiseFreqE) {
      l_rnd = cl_random_get(l_rnd);
      l_GSynExc = l_GSynExc + params->noiseAmpE*cl_random_prob(l_rnd);
   }

   l_rnd = cl_random_get(l_rnd);
   if (cl_random_prob(l_rnd) < dt_sec*params->noiseFreqI) {
      l_rnd = cl_random_get(l_rnd);
      l_GSynInh = l_GSynInh + params->noiseAmpI*cl_random_prob(l_rnd);
   }

   l_rnd = cl_random_get(l_rnd);
   if (cl_random_prob(l_rnd) < dt_sec*params->noiseFreqIB) {
      l_rnd = cl_random_get(l_rnd);
      l_GSynInhB = l_GSynInhB + params->noiseAmpIB*cl_random_prob(l_rnd);
   }
#else
   if (pv_random_prob() < dt_sec*params->noiseFreqE) {
      l_GSynExc = l_GSynExc + params->noiseAmpE*pv_random_prob();
   }

   if (pv_random_prob() < dt_sec*params->noiseFreqI) {
      l_GSynInh = l_GSynInh + params->noiseAmpI*pv_random_prob();
   }

   if (pv_random_prob() < dt_sec*params->noiseFreqIB) {
      l_GSynInhB = l_GSynInhB + params->noiseAmpIB*pv_random_prob();
   }
#endif

   const float GMAX = 10.0;

   // The portion of code below uses the newer method of calculating l_V.
   float G_E_initial, G_I_initial, G_IB_initial, G_E_final, G_I_final, G_IB_final;
   float dV1, dV2, dV;

   G_E_initial = l_G_E + l_GSynExc;
   G_I_initial = l_G_I + l_GSynInh;
   G_IB_initial = l_G_IB + l_GSynInhB;

   G_E_initial  = (G_E_initial  > GMAX) ? GMAX : G_E_initial;
   G_I_initial  = (G_I_initial  > GMAX) ? GMAX : G_I_initial;
   G_IB_initial = (G_IB_initial > GMAX) ? GMAX : G_IB_initial;

   G_E_final = G_E_initial * decayE;
   G_I_final = G_I_initial * decayI;
   G_IB_final = G_IB_initial * decayIB;

   l_G_Gap = l_GSynGap;

   dV1 = LIFGap_Vmem_derivative(l_V, G_E_initial, G_I_initial, G_IB_initial, l_G_Gap, Vexc, Vinh, VinhB, sum_gap, Vrest, tau);
   dV2 = LIFGap_Vmem_derivative(l_V+dt*dV1, G_E_final, G_I_final, G_IB_final, l_G_Gap, Vexc, Vinh, VinhB, sum_gap, Vrest, tau);
   dV = (dV1+dV2)*0.5;
   l_V = l_V + dt*dV;

   l_G_E = G_E_final;
   l_G_I = G_I_final;
   l_G_IB = G_IB_final;

   //l_Vth updates according to traditional LIF rule in addition to the slow threshold adaptation
   //      See LCA_Equations.pdf in the documentation for a full description of the neuron adaptive firing threshold.

   Vadpt[k] += (dt/tauTHR) * ((integratedSpikeCount[k]/tauO) - targetRatekHz) * (Vscale/targetRatekHz);

   l_Vth = Vadpt[k] + decayVth * (l_Vth - Vadpt[k]);

   bool fired_flag = (l_V > l_Vth);

   l_activ = fired_flag ? 1.0f             : 0.0f;
   l_V     = fired_flag ? Vrest            : l_V;
   l_Vth   = fired_flag ? l_Vth + deltaVth : l_Vth;
   l_G_IB  = fired_flag ? l_G_IB + 1.0f    : l_G_IB;

   //integratedSpikeCount is the trace activity of the neuron, with an exponential decay
   integratedSpikeCount[k] = decayO * (l_activ + integratedSpikeCount[k]);

   //
   // These actions must be done outside of kernel
   //    1. set activity to 0 in boundary (if needed)
   //    2. update active indices
   //

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

   activity[kex] = l_activ;

   V[k]   = l_V;
   Vth[k] = l_Vth;

   G_E[k]  = l_G_E; // G_E_final;
   G_I[k]  = l_G_I; // G_I_final;
   G_IB[k] = l_G_IB; // G_IB_final;
   G_Gap[k] = l_G_Gap;

   GSynExc[k]  = 0.0f;
   GSynInh[k]  = 0.0f;
   GSynInhB[k] = 0.0f;
   GSynGap[k]  = 0.0f;

#ifndef PV_USE_OPENCL
   } // loop over k
#endif

}


[OpenCL] Remove tests without triple from test/Headers/opencl-c-header.cl.

This test requires triples with Itanium C++ ABI whereas triples with MSVC environment uses Microsoft C++ ABI.

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

// RUN: %clang_cc1 -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.1| FileCheck %s
// RUN: %clang_cc1 -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.2| FileCheck %s
// RUN: %clang_cc1 -internal-isystem ../../lib/Headers -include opencl-c.h -fblocks -emit-llvm -o - %s -cl-std=CL2.0| FileCheck %s
// RUN: %clang_cc1 -triple spir-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple spir-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.1| FileCheck %s
// RUN: %clang_cc1 -triple spir-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.2| FileCheck %s
// RUN: %clang_cc1 -triple spir-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -fblocks -emit-llvm -o - %s -cl-std=CL2.0| FileCheck %s
// RUN: %clang_cc1 -triple spir64-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple spir64-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.1| FileCheck %s
// RUN: %clang_cc1 -triple spir64-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.2| FileCheck %s
// RUN: %clang_cc1 -triple spir64-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -fblocks -emit-llvm -o - %s -cl-std=CL2.0| FileCheck %s
// RUN: %clang_cc1 -triple amdgcn-unknown-amdhsa -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple amdgcn-unknown-amdhsa -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.1| FileCheck %s
// RUN: %clang_cc1 -triple amdgcn-unknown-amdhsa -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.2| FileCheck %s
// RUN: %clang_cc1 -triple amdgcn-unknown-amdhsa -internal-isystem ../../lib/Headers -include opencl-c.h -fblocks -emit-llvm -o - %s -cl-std=CL2.0| FileCheck %s
// RUN: %clang_cc1 -triple ppc64-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple ppc64-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.1| FileCheck %s
// RUN: %clang_cc1 -triple ppc64-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.2| FileCheck %s
// RUN: %clang_cc1 -triple ppc64-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -fblocks -emit-llvm -o - %s -cl-std=CL2.0| FileCheck %s
// RUN: %clang_cc1 -triple powerpc-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple powerpc-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.1| FileCheck %s
// RUN: %clang_cc1 -triple powerpc-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.2| FileCheck %s
// RUN: %clang_cc1 -triple powerpc-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -fblocks -emit-llvm -o - %s -cl-std=CL2.0| FileCheck %s
// RUN: %clang_cc1 -triple nvptx-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple nvptx-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.1| FileCheck %s
// RUN: %clang_cc1 -triple nvptx-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.2| FileCheck %s
// RUN: %clang_cc1 -triple nvptx-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -fblocks -emit-llvm -o - %s -cl-std=CL2.0| FileCheck %s
// RUN: %clang_cc1 -triple nvptx64-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple nvptx64-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.1| FileCheck %s
// RUN: %clang_cc1 -triple nvptx64-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -cl-std=CL1.2| FileCheck %s
// RUN: %clang_cc1 -triple nvptx64-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -fblocks -emit-llvm -o - %s -cl-std=CL2.0| FileCheck %s

// CHECK: _Z16convert_char_rtec
char f(char x) {
  return convert_char_rte(x);
}


Updated packet parsing function.

Updated packet parsing function.

#ifdef KERNEL_TEST_ENABLED
#include "../tests/kerneltypes.h"
#endif

#include "SharedMacros.h"
#include "SharedTypes.h"

/* Used to create, manipulate and access packet information. */
#define PKT_TYPE_SHIFT 0
#define PKT_DEST_SHIFT 2
#define PKT_ARG_SHIFT  10
#define PKT_SUB_SHIFT  14
#define PKT_TYPE_MASK  0x3      // 00000000000000000000000000000011
#define PKT_DEST_MASK  0x3FC    // 00000000000000000000001111111100
#define PKT_ARG_MASK   0x3C00   // 00000000000000000011110000000000
#define PKT_SUB_MASK   0xFFC000 // 00000000111111111100000000000000

/* Used to access symbol information. */
#define SYMBOL_KIND_SHIFT 63
#define SYMBOL_QUOTED_SHIFT 54
#define SYMBOL_KIND_MASK 0xF000000000000000
#define SYMBOL_QUOTED_MASK 0x00
#define SYMBOL_OPCODE_MASK 0xFFFFFFFF
#define SYMBOL_NAME_MASK 0xFFFFFFFF

/* Definition of symbol kinds. */
#define K_S 1
#define K_R 4
#define K_B 6

/* Used to access the information stored within a subtask record. */
#define NARGS_ABSENT_SHIFT   0
#define SUBTREC_STATUS_SHIFT 4
#define NARGS_ABSENT_MASK    0xF
#define SUBTREC_STATUS_MASK  0xF0

/* Packet Types. */
#define ERROR     0
#define REFERENCE 1
#define DATA      2

/* Subtask record status. */
#define NEW        0
#define PROCESSING 1
#define PENDING    2

/* Arg status. */
#define ABSENT     0
#define REQUESTING 1
#define PRESENT    2

/***********************************/
/******* Function Prototypes *******/
/***********************************/
void parse_pkt(packet p, __global uint2 *q, __global subt *table);

bool cunit_q_is_empty(size_t gid, __global uint2 *q, int n);
bool cunit_q_is_full(size_t gid, __global uint2 *q, int n);
uint cunit_q_size(size_t gid, __global uint2 *q, int n);
void transferRQ(__global uint2 *rq,  __global uint2 *q, int n);

void subt_store_payload(uint payload, uint arg_pos, ushort i, __global subt *subt);
bool subt_is_ready(ushort i, __global subt *subt);
__global subt_rec *subt_get_rec(ushort i, __global subt *subt);
bool subt_push(ushort i, __global subt *subt);
bool subt_pop(ushort *result, __global subt *subt);
bool subt_is_full(__global subt *subt);
bool subt_is_empty(__global subt *subt);
ushort subt_top(__global subt *subt);
void subt_set_top(__global subt *subt, ushort i);

uint subt_rec_get_service_id(__global subt_rec *r);
uint subt_rec_get_arg(__global subt_rec *r, uint arg_pos);
uint subt_rec_get_arg_status(__global subt_rec *r, uint arg_pos);
uint subt_rec_get_subt_status(__global subt_rec *r);
uint subt_rec_get_nargs_absent(__global subt_rec *r);
uint subt_rec_get_return_to(__global subt_rec *r);
uint subt_rec_get_return_as(__global subt_rec *r);
void subt_rec_set_service_id(__global subt_rec *r, uint service_id);
void subt_rec_set_arg(__global subt_rec *r, uint arg_pos, uint arg);
void subt_rec_set_arg_status(__global subt_rec *r, uint arg_pos, uint status);
void subt_rec_set_subt_status(__global subt_rec *r, uint status);
void subt_rec_set_nargs_absent(__global subt_rec *r, uint n);
void subt_rec_set_return_to(__global subt_rec *r, uint return_to);
void subt_rec_set_return_as(__global subt_rec *r, uint return_as);

uint pkt_get_type(packet p);
uint pkt_get_dest(packet p);
uint pkt_get_arg_pos(packet p);
uint pkt_get_sub(packet p);
uint pkt_get_payload(packet p);
void pkt_set_type(packet *p, uint type);
void pkt_set_dest(packet *p, uint dest);
void pkt_set_arg_pos(packet *p, uint arg);
void pkt_set_sub(packet *p, uint sub);
void pkt_set_payload(packet *p, uint payload);
packet pkt_create(uint type, uint dest, uint arg, uint sub, uint payload);

uint q_get_head_index(size_t id, size_t gid, __global uint2 *q, int n);
uint q_get_tail_index(size_t id, size_t gid, __global uint2 *q, int n);
void q_set_head_index(uint index, size_t id, size_t gid, __global uint2 *q, int n);
void q_set_tail_index(uint index, size_t id, size_t gid, __global uint2 *q, int n);
void q_set_last_op(uint type, size_t id, size_t gid,__global uint2 *q, int n);
bool q_last_op_is_read(size_t id, size_t gid, __global uint2 *q, int n);
bool q_last_op_is_write(size_t id, size_t gid, __global uint2 *q, int n);
bool q_is_empty(size_t id, size_t gid, __global uint2 *q, int n);
bool q_is_full(size_t id, size_t gid,__global uint2 *q, int n);
uint q_size(size_t id, size_t gid, __global uint2 *q, int n);
bool q_read(uint2 *result, size_t id, __global uint2 *q, int n);
bool q_write(uint2 value, size_t id, __global uint2 *q, int n);

/**************************/
/******* The Kernel *******/
/**************************/
__kernel void vm(__global packet *q,            /* Compute unit queues. */
                   __global packet *rq,           /* Transfer queues for READ state. */
                   int n,                         /* The number of compute units. */
                   __global int *state,           /* Are we in the READ or WRITE state? */
                   __global bytecode *cStore,     /* The code store. */
                   __global subt *subt,           /* The subtask table. */
                   __global char *in,             /* Input data from the host. */
                   __global char *result,         /* Memory to store the final results. */
                   __global char *scratch         /* Scratch memory for temporary results. */
                 ) {
  size_t gid = get_global_id(0);

  if (*state == WRITE) {
    transferRQ(rq, q, n);
  } else {
    for (int i = 0; i < n; i++) {
      packet p;
      while (q_read(&p, i, q, n)) {
        parse_pkt(p, rq, subt);
      }
    }
  }
}

uint symbol_get_kind(ulong s) {
  return (s & SYMBOL_KIND_MASK) >> SYMBOL_KIND_SHIFT;
}

bool symbol_is_quoted(ulong s) {
  return (s & SYMBOL_QUOTED_MASK) >> SYMBOL_QUOTED_SHIFT;
}

uint symbol_get_opcode(ulong s) {
  return s & SYMBOL_OPCODE_MASK;
}

uint symbol_get_name(ulong s) {
  return s & SYMBOL_NAME_MASK;
}

void parse_pkt(packet p, __global uint2 *q, __global subt *subt) {
  uint type = pkt_get_type(p);
  uint subtask = pkt_get_sub(p);
  uint arg_pos = pkt_get_arg_pos(p);
  uint payload = pkt_get_payload(p);

  switch (type) {
  case ERROR:
    break;
  case REFERENCE: // Create new subtask record.
    switch (symbol_get_kind(payload)) {
    case K_S:
      break;
    case K_R:
      if (!symbol_is_quoted(payload)) {
	uint dest = symbol_get_name(payload);
        packet p = pkt_create(REFERENCE, dest, arg_pos, subtask, payload);
      } else {

      }
      break;
    case K_B:
      break;
    }
    break;
  case DATA: // Store packet payload in associated subtask record.
    subt_store_payload(payload, arg_pos, subtask, subt);
    if (subt_is_ready(subtask, subt)) {
      // Perform computation
    }
    break;
  }
}

/**************************************/
/**** Compute Unit Queue Functions ****/
/**************************************/

/* Returns true if all queues owned by the specified compute unit are empty, false otherwise. */
bool cunit_q_is_empty(size_t gid, __global uint2 *q, int n) {
  for (int i = 0; i < n; i++) {
    if (!q_is_empty(gid, i, q, n)) {
      return false;
    }
  }

  return true;
}

/* Returns true if all queues owned by the specified compute unit are full, false otherwise. */
bool cunit_q_is_full(size_t gid, __global uint2 *q, int n) {
  for (int i = 0; i < n; i++) {
    if (!q_is_full(gid, i, q, n)) {
      return false;
    }
  }

  return true;
}

/* Return the total size of all compute unit owned queues. */
uint cunit_q_size(size_t gid, __global uint2 *q, int n) {
  uint size = 0;
  for (int i = 0; i < n; i++) {
    size += q_size(gid, i, q, n);
  }

  return size;
}

/* Copy all compute unit owned queue values from the readQueue into the real queues. */
void transferRQ(__global uint2 *rq, __global uint2 *q, int n) {
  uint2 packet;
  for (int i = 0; i < n; i++) {
    while (q_read(&packet, i, rq, n)) {
      q_write(packet, i, q, n);
    }
  }
}

/*********************************/
/**** Subtask Table Functions ****/
/*********************************/

void subt_store_payload(uint payload, uint arg_pos, ushort i, __global subt *subt) {
  __global subt_rec *rec = subt_get_rec(i, subt);
  uint nargs_absent = subt_rec_get_nargs_absent(rec) - 1;
  subt_rec_set_arg(rec, arg_pos, payload);
  subt_rec_set_arg_status(rec, arg_pos, PRESENT);
  subt_rec_set_nargs_absent(rec, nargs_absent);
}

bool subt_is_ready(ushort i, __global subt *subt) {
  __global subt_rec *rec = subt_get_rec(i, subt);
  return subt_rec_get_nargs_absent(rec) == 0;
}

__global subt_rec *subt_get_rec(ushort i, __global subt *subt) {
  return &(subt->recs[i]);
}

bool subt_push(ushort i, __global subt *subt) {
  if (subt_is_empty(subt)) {
    return false;
  }

  ushort top = subt_top(subt);
  subt->av_recs[top - 1] = i;
  subt_set_top(subt, top - 1);
  return true;
}

bool subt_pop(ushort *av_index, __global subt *subt) {
  if (subt_is_full(subt)) {
    return false;
  }

  ushort top = subt_top(subt);
  *av_index = subt->av_recs[top];
  subt_set_top(subt, top + 1);
  return true;
}

bool subt_is_full(__global subt *subt) {
  return subt_top(subt) == SUBT_SIZE + 1;
}

bool subt_is_empty(__global subt *subt) {
  return subt_top(subt) == 1;
}

ushort subt_top(__global subt *subt) {
  return subt->av_recs[0];
}

void subt_set_top(__global subt *subt, ushort i) {
  subt->av_recs[0] = i;
}

/**********************************/
/**** Subtask Record Functions ****/
/**********************************/
uint subt_rec_get_service_id(__global subt_rec *r) {
  return r->service_id;
}

uint subt_rec_get_arg(__global subt_rec *r, uint arg_pos) {
  return r->args[arg_pos];
}

uint subt_rec_get_arg_status(__global subt_rec *r, uint arg_pos) {
  return r->arg_status[arg_pos];
}

uint subt_rec_get_subt_status(__global subt_rec *r) {
  return (r->subt_status & SUBTREC_STATUS_MASK) >> SUBTREC_STATUS_SHIFT;
}

uint subt_rec_get_nargs_absent(__global subt_rec *r) {
  return (r->subt_status & NARGS_ABSENT_MASK);
}

uint subt_rec_get_return_to(__global subt_rec *r) {
  return r->return_to;
}

uint subt_rec_get_return_as(__global subt_rec *r) {
  return r->return_as;
}

void subt_rec_set_service_id(__global subt_rec *r, uint service_id) {
  r->service_id = service_id;
}

void subt_rec_set_arg(__global subt_rec *r, uint arg_pos, uint arg) {
  r->args[arg_pos] = arg;
}

void subt_rec_set_arg_status(__global subt_rec *r, uint arg_pos, uint status) {
  r->arg_status[arg_pos] = status;
}

void subt_rec_set_subt_status(__global subt_rec *r, uint status) {
  r->subt_status = (r->subt_status & ~SUBTREC_STATUS_MASK)
    | ((status << SUBTREC_STATUS_SHIFT) & SUBTREC_STATUS_MASK);
}

void subt_rec_set_nargs_absent(__global subt_rec *r, uint n) {
  r->subt_status = (r->subt_status & ~NARGS_ABSENT_MASK)
    | ((n << NARGS_ABSENT_SHIFT) & NARGS_ABSENT_MASK);
}

void subt_rec_set_return_to(__global subt_rec *r, uint return_to) {
  r->return_to = return_to;
}

void subt_rec_set_return_as(__global subt_rec *r, uint return_as) {
  r->return_as = return_as;
}

/**************************/
/**** Packet Functions ****/
/**************************/

/* Return the packet type. */
uint pkt_get_type(packet p) {
  return (p.x & PKT_TYPE_MASK) >> PKT_TYPE_SHIFT;
}

/* Return the packet destination address. */
uint pkt_get_dest(packet p) {
  return (p.x & PKT_DEST_MASK) >> PKT_DEST_SHIFT;
}

/* Return the packet argument position. */
uint pkt_get_arg_pos(packet p) {
  return (p.x & PKT_ARG_MASK) >> PKT_ARG_SHIFT;
}

/* Return the packet subtask. */
uint pkt_get_sub(packet p) {
  return (p.x & PKT_SUB_MASK) >> PKT_SUB_SHIFT;
}

/* Return the packet payload. */
uint pkt_get_payload(packet p) {
  return p.y;
}

/* Set the packet type. */
void pkt_set_type(packet *p, uint type) {
  (*p).x = ((*p).x & ~PKT_TYPE_MASK) | ((type << PKT_TYPE_SHIFT) & PKT_TYPE_MASK);
}

/* Set the packet destination address. */
void pkt_set_dest(packet *p, uint dest) {
  (*p).x = ((*p).x & ~PKT_DEST_MASK) | ((dest << PKT_DEST_SHIFT) & PKT_DEST_MASK);
}

/* Set the packet argument position. */
void pkt_set_arg_pos(packet *p, uint arg) {
  (*p).x = ((*p).x & ~PKT_ARG_MASK) | ((arg << PKT_ARG_SHIFT) & PKT_ARG_MASK);
}

/* Set the packet subtask. */
void pkt_set_sub(packet *p, uint sub) {
  (*p).x = ((*p).x & ~PKT_SUB_MASK) | ((sub << PKT_SUB_SHIFT) & PKT_SUB_MASK);
}

/* Set the packet payload. */
void pkt_set_payload(packet *p, uint payload) {
  (*p).y = payload;
}

/* Return a newly created packet. */
packet pkt_create(uint type, uint dest, uint arg, uint sub, uint payload) {
  packet p;
  pkt_set_type(&p, type);
  pkt_set_dest(&p, dest);
  pkt_set_arg_pos(&p, arg);
  pkt_set_sub(&p, sub);
  pkt_set_payload(&p, payload);
  return p;
}

/*************************/
/**** Queue Functions ****/
/*************************/

/* Returns the array index of the head element of the queue. */
uint q_get_head_index(size_t id, size_t gid, __global uint2 *q, int n) {
  ushort2 indices = as_ushort2(q[id * n + gid].x);
  return indices.x;
}

/* Returns the array index of the tail element of the queue. */
uint q_get_tail_index(size_t id, size_t gid,__global uint2 *q, int n) {
  ushort2 indices = as_ushort2(q[id * n + gid].x);
  return indices.y;
}

/* Set the array index of the head element of the queue. */
void q_set_head_index(uint index, size_t id, size_t gid, __global uint2 *q, int n) {
  ushort2 indices = as_ushort2(q[id * n + gid].x);
  indices.x = index;
  q[id * n + gid].x = as_uint(indices);
}

/* Set the array index of the tail element of the queue. */
void q_set_tail_index(uint index, size_t id, size_t gid,__global uint2 *q, int n) {
  ushort2 indices = as_ushort2(q[id * n + gid].x);
  indices.y = index;
  q[id * n + gid].x = as_uint(indices);
}

/* Set the type of the operation last performed on the queue. */
void q_set_last_op(uint type, size_t id, size_t gid, __global uint2 *q, int n) {
  q[id * n + gid].y = type;
}

/* Returns true if the last operation performed on the queue is a read, false otherwise. */
bool q_last_op_is_read(size_t id, size_t gid,__global uint2 *q, int n) {
  return q[id * n + gid].y == READ;
}

/* Returns true if the last operation performed on the queue is a write, false otherwise. */
bool q_last_op_is_write(size_t id, size_t gid,__global uint2 *q, int n) {
  return q[id * n + gid].y == WRITE;
}

/* Returns true if the queue is empty, false otherwise. */
bool q_is_empty(size_t id, size_t gid,  __global uint2 *q, int n) {
  return (q_get_head_index(id, gid, q, n) == q_get_tail_index(id, gid, q, n))
    && q_last_op_is_read(id, gid, q, n);
}

/* Returns true if the queue is full, false otherwise. */
bool q_is_full(size_t id, size_t gid, __global uint2 *q, int n) {
  return (q_get_head_index(id, gid, q, n) == q_get_tail_index(id, gid, q, n))
    && q_last_op_is_write(id, gid, q, n);
}

/* Return the size of the queue. */
uint q_size(size_t id, size_t gid, __global uint2 *q, int n) {
  if (q_is_full(id, gid, q, n)) return QUEUE_SIZE;
  if (q_is_empty(id, gid, q, n)) return 0;
  uint head = q_get_head_index(id, gid, q, n);
  uint tail = q_get_tail_index(id, gid, q, n);
  return (tail > head) ? (tail - head) : QUEUE_SIZE - head;
}

/* Read the value located at the head index of the queue into 'result'.
 * Returns true if succcessful (queue is not empty), false otherwise. */
bool q_read(uint2 *result, size_t id, __global uint2 *q, int n) {
  size_t gid = get_global_id(0);
  if (q_is_empty(gid, id, q, n)) {
    return false;
  }

  int index = q_get_head_index(gid, id, q, n);
  *result = q[(n*n) + (gid * n * QUEUE_SIZE) + (id * QUEUE_SIZE) + index];
  q_set_head_index((index + 1) % QUEUE_SIZE, gid, id, q, n);
  q_set_last_op(READ, gid, id, q, n);
  return true;
}

/* Write a value into the tail index of the queue.
 * Returns true if successful (queue is not full), false otherwise. */
bool q_write(uint2 value, size_t id, __global uint2 *q, int n) {
  size_t gid = get_global_id(0);
  if (q_is_full(id, gid, q, n)) {
    return false;
  }

  int index = q_get_tail_index(id, gid, q, n);
  q[(n*n) + (id * n * QUEUE_SIZE) + (gid * QUEUE_SIZE) + index] = value;
  q_set_tail_index((index + 1) % QUEUE_SIZE, id, gid, q, n);
  q_set_last_op(WRITE, id, gid, q, n);
  return true;
}

#ifdef KERNEL_TEST_ENABLED
#include "../tests/kerneltypes.h"
#endif

#include "SharedMacros.h"
#include "SharedTypes.h"

/* Used to create, manipulate and access packet information. */
#define PKT_TYPE_SHIFT 0
#define PKT_DEST_SHIFT 2
#define PKT_ARG_SHIFT  10
#define PKT_SUB_SHIFT  14
#define PKT_TYPE_MASK  0x3      // 00000000000000000000000000000011
#define PKT_DEST_MASK  0x3FC    // 00000000000000000000001111111100
#define PKT_ARG_MASK   0x3C00   // 00000000000000000011110000000000
#define PKT_SUB_MASK   0xFFC000 // 00000000111111111100000000000000

/* Used to access the information stored within a subtask record. */
#define NARGS_ABSENT_SHIFT   0
#define SUBTREC_STATUS_SHIFT 4
#define NARGS_ABSENT_MASK    0xF
#define SUBTREC_STATUS_MASK  0xF0

/* Packet Types. */
#define ERROR     0
#define REFERENCE 1
#define REQUEST   2
#define DATA      3

/* Subtask record status. */
#define NEW        0
#define PROCESSING 1
#define PENDING    2

/* Arg status. */
#define ABSENT     0
#define REQUESTING 1
#define PRESENT    2

/***********************************/
/******* Function Prototypes *******/
/***********************************/
void parse_pkt(packet p, __global subt *table);

bool cunit_q_is_empty(size_t gid, __global uint2 *q, int n);
bool cunit_q_is_full(size_t gid, __global uint2 *q, int n);
uint cunit_q_size(size_t gid, __global uint2 *q, int n);
void transferRQ(__global uint2 *rq,  __global uint2 *q, int n);

void subt_store_payload(uint payload, uint arg_pos, ushort i, __global subt *subt);
bool subt_is_ready(ushort i, __global subt *subt);
__global subt_rec *subt_get_rec(ushort i, __global subt *subt);
bool subt_push(ushort i, __global subt *subt);
bool subt_pop(ushort *result, __global subt *subt);
bool subt_is_full(__global subt *subt);
bool subt_is_empty(__global subt *subt);
ushort subt_top(__global subt *subt);
void subt_set_top(__global subt *subt, ushort i);

uint subt_rec_get_service_id(__global subt_rec *r);
uint subt_rec_get_arg(__global subt_rec *r, uint arg_pos);
uint subt_rec_get_arg_status(__global subt_rec *r, uint arg_pos);
uint subt_rec_get_subt_status(__global subt_rec *r);
uint subt_rec_get_nargs_absent(__global subt_rec *r);
uint subt_rec_get_return_to(__global subt_rec *r);
uint subt_rec_get_return_as(__global subt_rec *r);
void subt_rec_set_service_id(__global subt_rec *r, uint service_id);
void subt_rec_set_arg(__global subt_rec *r, uint arg_pos, uint arg);
void subt_rec_set_arg_status(__global subt_rec *r, uint arg_pos, uint status);
void subt_rec_set_subt_status(__global subt_rec *r, uint status);
void subt_rec_set_nargs_absent(__global subt_rec *r, uint n);
void subt_rec_set_return_to(__global subt_rec *r, uint return_to);
void subt_rec_set_return_as(__global subt_rec *r, uint return_as);

uint pkt_get_type(packet p);
uint pkt_get_dest(packet p);
uint pkt_get_arg_pos(packet p);
uint pkt_get_sub(packet p);
uint pkt_get_payload(packet p);
void pkt_set_type(packet *p, uint type);
void pkt_set_dest(packet *p, uint dest);
void pkt_set_arg_pos(packet *p, uint arg);
void pkt_set_sub(packet *p, uint sub);
void pkt_set_payload(packet *p, uint payload);
packet pkt_create(uint type, uint dest, uint arg, uint sub, uint payload);

uint q_get_head_index(size_t id, size_t gid, __global uint2 *q, int n);
uint q_get_tail_index(size_t id, size_t gid, __global uint2 *q, int n);
void q_set_head_index(uint index, size_t id, size_t gid, __global uint2 *q, int n);
void q_set_tail_index(uint index, size_t id, size_t gid, __global uint2 *q, int n);
void q_set_last_op(uint type, size_t id, size_t gid,__global uint2 *q, int n);
bool q_last_op_is_read(size_t id, size_t gid, __global uint2 *q, int n);
bool q_last_op_is_write(size_t id, size_t gid, __global uint2 *q, int n);
bool q_is_empty(size_t id, size_t gid, __global uint2 *q, int n);
bool q_is_full(size_t id, size_t gid,__global uint2 *q, int n);
uint q_size(size_t id, size_t gid, __global uint2 *q, int n);
bool q_read(uint2 *result, size_t id, __global uint2 *q, int n);
bool q_write(uint2 value, size_t id, __global uint2 *q, int n);

/**************************/
/******* The Kernel *******/
/**************************/
__kernel void vm(__global packet *q,            /* Compute unit queues. */
                 __global packet *rq,           /* Transfer queues for READ state. */
                 int n,                         /* The number of compute units. */
                 __global int *state,           /* Are we in the READ or WRITE state? */
                 __global bytecode *cStore,     /* The code store. */
                 __global subt *subt,           /* The subtask table. */
                 __global char *in,             /* Input data from the host. */
                 __global char *result,         /* Memory to store the final results. */
                 __global char *scratch         /* Scratch memory for temporary results. */
                 ) {
  size_t gid = get_global_id(0);

  if (*state == WRITE) {
    transferRQ(rq, q, n);
  } else {
    for (int i = 0; i < n; i++) {
      packet p;
      while (q_read(&p, i, q, n)) {
        parse_pkt(p, subt);
      }
    }
  }
}

void parse_pkt(packet p, __global subt *subt) {
  uint type = pkt_get_type(p);
  uint subtask = pkt_get_sub(p);
  uint arg_pos = pkt_get_arg_pos(p);
  uint payload = pkt_get_payload(p);

  switch (type) {
  case ERROR:
    break;
  case REFERENCE: // Create new subtask record.
    break;
  case REQUEST:
    break;
  case DATA: // Store packet payload in associated subtask record.
    subt_store_payload(payload, arg_pos, subtask, subt);
    if (subt_is_ready(subtask, subt)) {
      // Perform computation
    }
    break;
  }
}

/**************************************/
/**** Compute Unit Queue Functions ****/
/**************************************/

/* Returns true if all queues owned by the specified compute unit are empty, false otherwise. */
bool cunit_q_is_empty(size_t gid, __global uint2 *q, int n) {
  for (int i = 0; i < n; i++) {
    if (!q_is_empty(gid, i, q, n)) {
      return false;
    }
  }

  return true;
}

/* Returns true if all queues owned by the specified compute unit are full, false otherwise. */
bool cunit_q_is_full(size_t gid, __global uint2 *q, int n) {
  for (int i = 0; i < n; i++) {
    if (!q_is_full(gid, i, q, n)) {
      return false;
    }
  }

  return true;
}

/* Return the total size of all compute unit owned queues. */
uint cunit_q_size(size_t gid, __global uint2 *q, int n) {
  uint size = 0;
  for (int i = 0; i < n; i++) {
    size += q_size(gid, i, q, n);
  }

  return size;
}

/* Copy all compute unit owned queue values from the readQueue into the real queues. */
void transferRQ(__global uint2 *rq, __global uint2 *q, int n) {
  uint2 packet;
  for (int i = 0; i < n; i++) {
    while (q_read(&packet, i, rq, n)) {
      q_write(packet, i, q, n);
    }
  }
}

/*********************************/
/**** Subtask Table Functions ****/
/*********************************/

void subt_store_payload(uint payload, uint arg_pos, ushort i, __global subt *subt) {
  __global subt_rec *rec = subt_get_rec(i, subt);
  uint nargs_absent = subt_rec_get_nargs_absent(rec) - 1;
  subt_rec_set_arg(rec, arg_pos, payload);
  subt_rec_set_arg_status(rec, arg_pos, PRESENT);
  subt_rec_set_nargs_absent(rec, nargs_absent);
}

bool subt_is_ready(ushort i, __global subt *subt) {
  __global subt_rec *rec = subt_get_rec(i, subt);
  return subt_rec_get_nargs_absent(rec) == 0;
}

__global subt_rec *subt_get_rec(ushort i, __global subt *subt) {
  return &(subt->recs[i]);
}

bool subt_push(ushort i, __global subt *subt) {
  if (subt_is_empty(subt)) {
    return false;
  }

  ushort top = subt_top(subt);
  subt->av_recs[top - 1] = i;
  subt_set_top(subt, top - 1);
  return true;
}

bool subt_pop(ushort *av_index, __global subt *subt) {
  if (subt_is_full(subt)) {
    return false;
  }

  ushort top = subt_top(subt);
  *av_index = subt->av_recs[top];
  subt_set_top(subt, top + 1);
  return true;
}

bool subt_is_full(__global subt *subt) {
  return subt_top(subt) == SUBT_SIZE + 1;
}

bool subt_is_empty(__global subt *subt) {
  return subt_top(subt) == 1;
}

ushort subt_top(__global subt *subt) {
  return subt->av_recs[0];
}

void subt_set_top(__global subt *subt, ushort i) {
  subt->av_recs[0] = i;
}

/**********************************/
/**** Subtask Record Functions ****/
/**********************************/
uint subt_rec_get_service_id(__global subt_rec *r) {
  return r->service_id;
}

uint subt_rec_get_arg(__global subt_rec *r, uint arg_pos) {
  return r->args[arg_pos];
}

uint subt_rec_get_arg_status(__global subt_rec *r, uint arg_pos) {
  return r->arg_status[arg_pos];
}

uint subt_rec_get_subt_status(__global subt_rec *r) {
  return (r->subt_status & SUBTREC_STATUS_MASK) >> SUBTREC_STATUS_SHIFT;
}

uint subt_rec_get_nargs_absent(__global subt_rec *r) {
  return (r->subt_status & NARGS_ABSENT_MASK);
}

uint subt_rec_get_return_to(__global subt_rec *r) {
  return r->return_to;
}

uint subt_rec_get_return_as(__global subt_rec *r) {
  return r->return_as;
}

void subt_rec_set_service_id(__global subt_rec *r, uint service_id) {
  r->service_id = service_id;
}

void subt_rec_set_arg(__global subt_rec *r, uint arg_pos, uint arg) {
  r->args[arg_pos] = arg;
}

void subt_rec_set_arg_status(__global subt_rec *r, uint arg_pos, uint status) {
  r->arg_status[arg_pos] = status;
}

void subt_rec_set_subt_status(__global subt_rec *r, uint status) {
  r->subt_status = (r->subt_status & ~SUBTREC_STATUS_MASK)
    | ((status << SUBTREC_STATUS_SHIFT) & SUBTREC_STATUS_MASK);
}

void subt_rec_set_nargs_absent(__global subt_rec *r, uint n) {
  r->subt_status = (r->subt_status & ~NARGS_ABSENT_MASK)
    | ((n << NARGS_ABSENT_SHIFT) & NARGS_ABSENT_MASK);
}

void subt_rec_set_return_to(__global subt_rec *r, uint return_to) {
  r->return_to = return_to;
}

void subt_rec_set_return_as(__global subt_rec *r, uint return_as) {
  r->return_as = return_as;
}

/**************************/
/**** Packet Functions ****/
/**************************/

/* Return the packet type. */
uint pkt_get_type(packet p) {
  return (p.x & PKT_TYPE_MASK) >> PKT_TYPE_SHIFT;
}

/* Return the packet destination address. */
uint pkt_get_dest(packet p) {
  return (p.x & PKT_DEST_MASK) >> PKT_DEST_SHIFT;
}

/* Return the packet argument position. */
uint pkt_get_arg_pos(packet p) {
  return (p.x & PKT_ARG_MASK) >> PKT_ARG_SHIFT;
}

/* Return the packet subtask. */
uint pkt_get_sub(packet p) {
  return (p.x & PKT_SUB_MASK) >> PKT_SUB_SHIFT;
}

/* Return the packet payload. */
uint pkt_get_payload(packet p) {
  return p.y;
}

/* Set the packet type. */
void pkt_set_type(packet *p, uint type) {
  (*p).x = ((*p).x & ~PKT_TYPE_MASK) | ((type << PKT_TYPE_SHIFT) & PKT_TYPE_MASK);
}

/* Set the packet destination address. */
void pkt_set_dest(packet *p, uint dest) {
  (*p).x = ((*p).x & ~PKT_DEST_MASK) | ((dest << PKT_DEST_SHIFT) & PKT_DEST_MASK);
}

/* Set the packet argument position. */
void pkt_set_arg_pos(packet *p, uint arg) {
  (*p).x = ((*p).x & ~PKT_ARG_MASK) | ((arg << PKT_ARG_SHIFT) & PKT_ARG_MASK);
}

/* Set the packet subtask. */
void pkt_set_sub(packet *p, uint sub) {
  (*p).x = ((*p).x & ~PKT_SUB_MASK) | ((sub << PKT_SUB_SHIFT) & PKT_SUB_MASK);
}

/* Set the packet payload. */
void pkt_set_payload(packet *p, uint payload) {
  (*p).y = payload;
}

/* Return a newly created packet. */
packet pkt_create(uint type, uint dest, uint arg, uint sub, uint payload) {
  packet p;
  pkt_set_type(&p, type);
  pkt_set_dest(&p, dest);
  pkt_set_arg_pos(&p, arg);
  pkt_set_sub(&p, sub);
  pkt_set_payload(&p, payload);
  return p;
}

/*************************/
/**** Queue Functions ****/
/*************************/

/* Returns the array index of the head element of the queue. */
uint q_get_head_index(size_t id, size_t gid, __global uint2 *q, int n) {
  ushort2 indices = as_ushort2(q[id * n + gid].x);
  return indices.x;
}

/* Returns the array index of the tail element of the queue. */
uint q_get_tail_index(size_t id, size_t gid,__global uint2 *q, int n) {
  ushort2 indices = as_ushort2(q[id * n + gid].x);
  return indices.y;
}

/* Set the array index of the head element of the queue. */
void q_set_head_index(uint index, size_t id, size_t gid, __global uint2 *q, int n) {
  ushort2 indices = as_ushort2(q[id * n + gid].x);
  indices.x = index;
  q[id * n + gid].x = as_uint(indices);
}

/* Set the array index of the tail element of the queue. */
void q_set_tail_index(uint index, size_t id, size_t gid,__global uint2 *q, int n) {
  ushort2 indices = as_ushort2(q[id * n + gid].x);
  indices.y = index;
  q[id * n + gid].x = as_uint(indices);
}

/* Set the type of the operation last performed on the queue. */
void q_set_last_op(uint type, size_t id, size_t gid, __global uint2 *q, int n) {
  q[id * n + gid].y = type;
}

/* Returns true if the last operation performed on the queue is a read, false otherwise. */
bool q_last_op_is_read(size_t id, size_t gid,__global uint2 *q, int n) {
  return q[id * n + gid].y == READ;
}

/* Returns true if the last operation performed on the queue is a write, false otherwise. */
bool q_last_op_is_write(size_t id, size_t gid,__global uint2 *q, int n) {
  return q[id * n + gid].y == WRITE;
}

/* Returns true if the queue is empty, false otherwise. */
bool q_is_empty(size_t id, size_t gid,  __global uint2 *q, int n) {
  return (q_get_head_index(id, gid, q, n) == q_get_tail_index(id, gid, q, n))
    && q_last_op_is_read(id, gid, q, n);
}

/* Returns true if the queue is full, false otherwise. */
bool q_is_full(size_t id, size_t gid, __global uint2 *q, int n) {
  return (q_get_head_index(id, gid, q, n) == q_get_tail_index(id, gid, q, n))
    && q_last_op_is_write(id, gid, q, n);
}

/* Return the size of the queue. */
uint q_size(size_t id, size_t gid, __global uint2 *q, int n) {
  if (q_is_full(id, gid, q, n)) return QUEUE_SIZE;
  if (q_is_empty(id, gid, q, n)) return 0;
  uint head = q_get_head_index(id, gid, q, n);
  uint tail = q_get_tail_index(id, gid, q, n);
  return (tail > head) ? (tail - head) : QUEUE_SIZE - head;
}

/* Read the value located at the head index of the queue into 'result'.
 * Returns true if succcessful (queue is not empty), false otherwise. */
bool q_read(uint2 *result, size_t id, __global uint2 *q, int n) {
  size_t gid = get_global_id(0);
  if (q_is_empty(gid, id, q, n)) {
    return false;
  }

  int index = q_get_head_index(gid, id, q, n);
  *result = q[(n*n) + (gid * n * QUEUE_SIZE) + (id * QUEUE_SIZE) + index];
  q_set_head_index((index + 1) % QUEUE_SIZE, gid, id, q, n);
  q_set_last_op(READ, gid, id, q, n);
  return true;
}

/* Write a value into the tail index of the queue.
 * Returns true if successful (queue is not full), false otherwise. */
bool q_write(uint2 value, size_t id, __global uint2 *q, int n) {
  size_t gid = get_global_id(0);
  if (q_is_full(id, gid, q, n)) {
    return false;
  }

  int index = q_get_tail_index(id, gid, q, n);
  q[(n*n) + (id * n * QUEUE_SIZE) + (gid * QUEUE_SIZE) + index] = value;
  q_set_tail_index((index + 1) % QUEUE_SIZE, id, gid, q, n);
  q_set_last_op(WRITE, id, gid, q, n);
  return true;
}


Removed warnings in kernel

Removed warnings in kernel

#define WRAP_BOUNDS 0
#define IX(i,j,k) ((i) + ((j)*(NX)) + ((k)*(NX)*(NY)))
#define IXL(i,j,k) ((i) + ((j)*(BLOCK_SIZE_WITH_PAD)) + ((k)*(BLOCK_SIZE_WITH_PAD)*(BLOCK_SIZE_WITH_PAD)))
#define LERP(a,b,t) (((1.0)-(t))*(a) + ((t)*(b)))

int mod_int (int a, int b)
{
  if(b < 0) //you can check for b == 0 separately and do what you want
    return mod_int(-a, -b);
  int ret = a % b;
  if(ret < 0)
    ret+=b;
  return ret;
}

float get_data(__global float * x, int i, int j, int k)
{
  //If I basically have a 2D grid then the 3 way check gives bad results
  //if(i < 0 || i >= NX || j < 0 || j >= NY || k < 0 || k >= NZ)
  //if(i < 0 || i >= NX || j < 0 || j >= NY)
  //{
  //	return 0.0f;
  //}

  i = clamp(i,0,NX-1);
  j = clamp(j,0,NY-1);
  k = clamp(k,0,NZ-1);

  return x[IX(i,j,k)];
}

float get_data_local(__local float * x, int i, int j, int k)
{
  i = clamp(i,0,BLOCK_SIZE_WITH_PAD-1);
  j = clamp(j,0,BLOCK_SIZE_WITH_PAD-1);
  k = clamp(k,0,BLOCK_SIZE_WITH_PAD-1);

  return x[IXL(i,j,k)];
}

float get_interpolated_value(
      __global float * x,
      float3 pos,
      float h)
{
   float3 ph = pos/h;
	//The grid world pos is 0-1.
   int3 idx0 = {convert_int(ph.x), convert_int(ph.y), convert_int(ph.z)};
   int3 idx1 = {
            convert_int(clamp(idx0.x + 1, 0,NX-1)),
	          convert_int(clamp(idx0.y + 1, 0,NY-1)),
            convert_int(clamp(idx0.z + 1, 0,NZ-1))
            };

	//Calculate t per component
   //float it,jt,kt;
   float3 t = {
            pos.x - idx0.x*h,
            pos.y - idx0.y*h,
            pos.z - idx0.z*h
            };

	//assert (t.x < 1.0 && t.x >= 0);
	//assert (t.y < 1.0 && t.y >= 0);
	//assert (t.z < 1.0 && t.z >= 0);

	// Assume a cube wt.xh 8 points
	//Front face
	//Top Front Lerp
	float xFrontLeftTop = x[IX(idx0.x,idx1.y,idx0.z)];
	float xFrontRightTop = x[IX(idx1.x,idx1.y,idx0.z)];
	float xFrontTopInterp = mix(xFrontLeftTop, xFrontRightTop, t.x);
	//Bottom Front Lerp
	float xFrontLeftBottom = x[IX(idx0.x,idx0.y,idx0.z)];
	float xFrontRightBottom = x[IX(idx1.x,idx0.y,idx0.z)];
	float xFrontBottomInterp = mix(xFrontLeftBottom, xFrontRightBottom, t.x);

	//Back face
	//Top Back Lerp
	float xBackLeftTop = x[IX(idx0.x,idx1.y,idx1.z)];
	float xBackRightTop = x[IX(idx1.x,idx1.y,idx1.z)];
	float xBackTopInterp = mix(xBackLeftTop, xBackRightTop, t.x);
	//Bottom Back Lerp
	float xBackLeftBottom = x[IX(idx0.x,idx0.y,idx1.z)];
	float xBackRightBottom = x[IX(idx1.x,idx0.y,idx1.z)];
	float xBackBottomInterp = mix(xBackLeftBottom, xBackRightBottom, t.x);

	//Now get middle of front -The bilinear interp of the front face
	float xBiLerpFront = mix(xFrontBottomInterp, xFrontTopInterp,t.y);

	//Now get middle of back -The bilinear interp of the back face
	float xBiLerpBack = mix(xBackBottomInterp, xBackTopInterp, t.y);

	//Now get the interpolated point between the points calculated in
   //the front and back faces - The trilinear interp part
	float xTriLerp = mix(xBiLerpFront, xBiLerpBack, t.z);

	return xTriLerp;
}

__kernel void advect_forward_euler(
      const float delta_time,
      int3  dims,
      const float H,
      __global float *q,
      __global float * q_prev,
      __global float * u_prev,
      __global float * v_prev,
      __global float * w_prev
//      __global float4 * debugData1,
//      __global float4 * debugData2,
//      __global float4 * debugData3
                                   )
{
  int id = get_global_id(0);

  float dt = -delta_time*NX;

  int slice_size = NX*NY;
  int row_size = NX;
  int k = id / slice_size;
  int j = (id - k*slice_size) / row_size;
  int i = id - j*row_size - k*slice_size;

  float3 pos = {i*H, j*H, k*H};

  //debugData1[id] = pos.xyzx;

  float3 orig_vel = {
           u_prev[IX(i,j,k)],
           v_prev[IX(i,j,k)],
           w_prev[IX(i,j,k)]
  };

  //debugData1[id] = orig_vel.xyzx;

  float3 new_pos = {
           pos.x+(dt*orig_vel.x),
           pos.y+(dt*orig_vel.y),
           pos.z+(dt*orig_vel.z)
  };

  //debugData1[id] = new_pos.xyzx;

#if !WRAP_BOUNDS
	new_pos.x   = clamp(new_pos.x,0.0f,NX-1.0f);
	new_pos.y   = clamp(new_pos.y,0.0f,NY-1.0f);
	new_pos.z   = clamp(new_pos.z,0.0f,NZ-1.0f);
#endif

  //Have to interpolate at new point
	float traced_q;
  traced_q = get_interpolated_value( q_prev, new_pos, H);

  q[id] = traced_q;

}

__kernel void advectRK2(
            const float delta_time,
            int3  dims,
            const float H,
            __global float *q,
            __global float * q_prev,
            __global float * u_prev,
            __global float * v_prev,
            __global float * w_prev
//            __global float4 * debugData1,
//            __global float4 * debugData2,
//            __global float4 * debugData3
                        )
{
  int id = get_global_id(0);

	float dt = -delta_time*NX;

	//FOR_EACH_FACE
	//{
  int slice_size = NX*NY;
  int row_size = NX;
  int k = id / slice_size;
  int j = (id - k*slice_size) / row_size;
  int i = id - j*row_size - k*slice_size;

  float3 pos = {i*H, j*H, k*H};
  float3 orig_vel = {u_prev[IX(i,j,k)],v_prev[IX(i,j,k)],w_prev[IX(i,j,k)]};

  //RK2
  // What is u(x)?  value(such as velocity) at x i guess
  //y = x + dt*u(x + (dt/2)*u(x))

  //backtrace based upon current velocity at cell center.
  float halfDT = 0.5f*dt;
  float3 halfway_position = {
    pos.x+(halfDT*orig_vel.x),
    pos.y+(halfDT*orig_vel.y),
    pos.z+(halfDT*orig_vel.z)
  };

#if !WRAP_BOUNDS
  halfway_position.x  = clamp(halfway_position.x,0.0f,NX-1.0f);
  halfway_position.y  = clamp(halfway_position.y,0.0f,NY-1.0f);
  halfway_position.z  = clamp(halfway_position.z,0.0f,NZ-1.0f);
#endif

  float3 halfway_vel;
  halfway_vel.x = get_interpolated_value(u_prev, halfway_position,H);
  halfway_vel.y = get_interpolated_value(v_prev, halfway_position,H);
  halfway_vel.z = get_interpolated_value(w_prev, halfway_position,H);

  float3 backtraced_position;
  backtraced_position.x  = pos.x + dt*halfway_vel.x;
  backtraced_position.y  = pos.y + dt*halfway_vel.y;
  backtraced_position.z  = pos.z + dt*halfway_vel.z;

#if !WRAP_BOUNDS
  backtraced_position.x  = clamp(backtraced_position.x,0.0f,NX-1.0f);
  backtraced_position.y  = clamp(backtraced_position.y,0.0f,NY-1.0f);
  backtraced_position.z  = clamp(backtraced_position.z,0.0f,NZ-1.0f);
#endif

  //Have to interpolate at new point
  float traced_q;
  traced_q = get_interpolated_value(q_prev, backtraced_position,H);

  //Has to be set on u
  q[IX(i,j,k)] = traced_q;

	//}
}

__kernel void advect_velocity_RK2(
                         const float delta_time,
                         int3  dims,
                         const float H,
                         __global float * u,
                         __global float * v,
                         __global float * w,
                         __global float * u_prev,
                         __global float * v_prev,
                         __global float * w_prev
//                         __global float4 * debugData1,
//                         __global float4 * debugData2,
//                         __global float4 * debugData3
                                  )

{
  int id = get_global_id(0);

	float dt = -delta_time*NX;

  int slice_size = NX*NY;
  int row_size = NX;
  int k = id / slice_size;
  int j = (id - k*slice_size) / row_size;
  int i = id - j*row_size - k*slice_size;

  float3 pos = {i*H,j*H,k*H};
  float3 orig_vel = {u_prev[IX(i,j,k)],v_prev[IX(i,j,k)],w_prev[IX(i,j,k)]};

  //RK2
  // What is u(x)?  value(such as velocity) at x i guess
  //y = x + dt*u(x + (dt/2)*u(x))

  //backtrace based upon current velocity at cell center.
  float halfDT = 0.5f*dt;
  float3 halfway_position = {
    pos.x+(halfDT*orig_vel.x),
    pos.y+(halfDT*orig_vel.y),
    pos.z+(halfDT*orig_vel.z)
  };

#if !WRAP_BOUNDS
  halfway_position.x  = clamp(halfway_position.x,0.0f,NX-1.0f);
  halfway_position.y  = clamp(halfway_position.y,0.0f,NY-1.0f);
  halfway_position.z  = clamp(halfway_position.z,0.0f,NZ-1.0f);
#endif

  float3 halfway_vel;
  halfway_vel.x = get_interpolated_value(u_prev, halfway_position,H);
  halfway_vel.y = get_interpolated_value(v_prev, halfway_position,H);
  halfway_vel.z = get_interpolated_value(w_prev, halfway_position,H);

  float3 backtraced_position;
  backtraced_position.x  = pos.x + dt*halfway_vel.x;
  backtraced_position.y  = pos.y + dt*halfway_vel.y;
  backtraced_position.z  = pos.z + dt*halfway_vel.z;

#if !WRAP_BOUNDS
  backtraced_position.x  = clamp(backtraced_position.x,0.0f,NX-1.0f);
  backtraced_position.y  = clamp(backtraced_position.y,0.0f,NY-1.0f);
  backtraced_position.z  = clamp(backtraced_position.z,0.0f,NZ-1.0f);
#endif

  //Have to interpolate at new point
  float3 traced_velocity;
  traced_velocity.x = get_interpolated_value(u_prev, backtraced_position,H);
  traced_velocity.y = get_interpolated_value(v_prev, backtraced_position,H);
  traced_velocity.z = get_interpolated_value(w_prev, backtraced_position,H);

  //Has to be set on u
  u[IX(i,j,k)] = traced_velocity.x;
  v[IX(i,j,k)] = traced_velocity.y;
  w[IX(i,j,k)] = traced_velocity.z;

}

__kernel void advect_velocity_forward_euler(
                                  const float delta_time,
                                  int3  dims,
                                  const float H,
                                  __global float * u,
                                  __global float * v,
                                  __global float * w,
                                  __global float * u_prev,
                                  __global float * v_prev,
                                  __global float * w_prev
//                                  __global float4 * debugData1,
//                                  __global float4 * debugData2,
//                                  __global float4 * debugData3
                                            )

{
  int id = get_global_id(0);
  int slice_size = NX*NY;
  int row_size = NX;
  int k = id / slice_size;
  int j = (id - k*slice_size) / row_size;
  int i = id - j*row_size - k*slice_size;

  float dt =  -delta_time * NX;

  float3 pos = {i*H,j*H,k*H};
  float3 orig_vel = {u_prev[IX(i,j,k)],v_prev[IX(i,j,k)],w_prev[IX(i,j,k)]};

  float3 new_pos = {
    pos.x+(dt*orig_vel.x),
    pos.y+(dt*orig_vel.y),
    pos.z+(dt*orig_vel.z)
  };

#if !WRAP_BOUNDS
  new_pos.x  = clamp(new_pos.x,0.0f,NX-1.0f);
  new_pos.y  = clamp(new_pos.y,0.0f,NY-1.0f);
  new_pos.z  = clamp(new_pos.z,0.0f,NZ-1.0f);
#endif

  float3 new_vel;
  new_vel.x = get_interpolated_value(u_prev, new_pos,H);
  new_vel.y = get_interpolated_value(v_prev, new_pos,H);
  new_vel.z = get_interpolated_value(w_prev, new_pos,H);

  //Has to be set on u
  u[IX(i,j,k)] = new_vel.x;
  v[IX(i,j,k)] = new_vel.y;
  w[IX(i,j,k)] = new_vel.z;

//  if(id == 112)
//  {
//    printf("dt = %3.2f\n",dt);
//    printf("NX = %d\n",NX);
//    printf("pos = %3.2f,%3.2f,%3.2f\n",pos.x,pos.y,pos.z);
//    printf("new_pos = %3.2f,%3.2f,%3.2f\n",new_pos.x,new_pos.y,new_pos.z);
//
//  }
//
}

float4 safe_normalize(float4 p)
{
  float4 v = p;
  float l = length(v);
  if(l > 0.0f)
  {
    v = normalize(v);
  }
  else
  {
    v.xyzw =  0.0f;
  }
  return v;
}

float4 get_curl(
                __global float * u,
                __global float * v,
                __global float * w,
                int i, int j, int k)
{
	float dwdj = 0.5f*(get_data(w, i, j+1, k) - get_data(w,i, j-1, k));
	float dwdi = 0.5f*(get_data(w, i+1, j, k) - get_data(w,i-1, j, k));

	float dudk = 0.5f*(get_data(u, i, j, k+1)-get_data(u, i, j, k-1));
	float dudj = 0.5f*(get_data(u, i, j+1, k)-get_data(u, i, j-1, k));

	float dvdk = 0.5f*(get_data(v, i, j, k+1)-get_data(v, i, j, k-1));
	float dvdi = 0.5f*(get_data(v, i+1, j, k)-get_data(v, i-1, j, k));

  float4 out = {dwdj-dvdk, dudk-dwdi, dvdi-dudj,0.0f};
  return out;
}

__kernel void vorticity_confinement(__global float *u,
                                    __global float *v,
                                    __global float* w,
                                    __global float * u_prev,
                                    __global float * v_prev,
                                    __global float * w_prev,
                                    int3 n,
                                    float e,
                                    float dt)
{
  int id = get_global_id(0);
  int slice_size = NX*NY;
  int row_size = NX;
  int k = id / slice_size;
  int j = (id - k*slice_size) / row_size;
  int i = id - j*row_size - k*slice_size;

  //if(i < 1 || j < 1 || (NZ > 1 && k < 1) || i > NX -1 || j > NY-1 || (NZ > 1 && k > NZ-1) || (NZ == 1 && k > 1))
  if(i < 1 || j < 1 || k < 0 || i >= NX -1 || j >= NY-1 ||  k > NZ )
    return;

	float4 curl;
  float4 curl_iplus1;
  float4 curl_iminus1;
  float4 curl_jplus1;
  float4 curl_jminus1;
  float4 curl_kplus1;
  float4 curl_kminus1;

  float4 norm;
  float4 f;

    // calculate gradient of curl magnitude
    curl_iplus1 = get_curl(u_prev,v_prev, w_prev, i+1, j, k);
    curl_iminus1= get_curl(u_prev,v_prev, w_prev, i-1, j, k);

    curl_jplus1 = get_curl(u_prev,v_prev, w_prev, i, j+1, k);
    curl_jminus1= get_curl(u_prev,v_prev, w_prev, i, j-1, k);

    curl_kplus1 = get_curl(u_prev,v_prev, w_prev, i, j, k+1);
    curl_kminus1 = get_curl(u_prev,v_prev, w_prev, i, j, k-1);

    float dcdi = 0.5f*(length(curl_iplus1) - length(curl_iminus1));
    float dcdj = 0.5f*(length(curl_jplus1) - length(curl_jminus1));
    float dcdk = 0.5f*(length(curl_kplus1) - length(curl_kminus1));

    norm.x = dcdi;
    norm.y = dcdj;
    norm.z = dcdk;
    norm.w = 0.0f;

    norm = safe_normalize(norm);

    curl = get_curl(u_prev,v_prev, w_prev, i, j, k);

    //float e = 0.5f;

    f = cross(norm, curl);

    u[IX(i,j,k)] += f.x * e * dt;
    v[IX(i,j,k)] += f.y * e * dt;
    w[IX(i,j,k)] += f.z * e * dt;

}

__kernel void calculate_divergence(
            __global float *divergence,
            __global float *u,
            __global float *v,
            __global float *w,
           // int i, int j, int k,
            int3 n,
            float dt )
{
	{
    int id = get_global_id(0);
    int slice_size = NX*NY;
    int row_size = NX;
    int k = id / slice_size;
    int j = (id - k*slice_size) / row_size;
    int i = id - j*row_size - k*slice_size;

		float du = get_data(u,i+1,j,k) - get_data(u,i-1,j,k);
		float dv = get_data(v,i,j+1,k) - get_data(v,i,j-1,k);
		float dw = get_data(w,i,j,k+1) - get_data(w,i,j,k-1);
		float div = 0.5f*(du + dv + dw);

		divergence[IX(i,j,k)] = div;

    barrier(CLK_GLOBAL_MEM_FENCE);
	}
}

__kernel void zero_pressure( __global float *pressure)
{
  int id = get_global_id(0);

	pressure[id]  = 0.0f;

}

__kernel void vector_dot_product(
                                    __global float* a,
                                    __global float* b,
                                    int n) {

}

__kernel void laplacian_mtx_vec_mult(
                                     __global float *out,
                                     __global float* x,
                                     int3 n) {

  int id = get_global_id(0);
  int slice_size = NX*NY;
  int row_size = NX;
  int k = id / slice_size;
  int j = (id - k*slice_size) / row_size;
  int i = id - j*row_size - k*slice_size;

  float sum = 0.0f;
  sum += -6.0f * x[id];
  sum += get_data(x,i-1,j,k);
  sum += get_data(x,i+1,j,k);
  sum += get_data(x,i,j-1,k);
  sum += get_data(x,i,j+1,k);
  sum += get_data(x,i,j,k-1);
  sum += get_data(x,i,j,k+1);

  out[id] = sum;
}

__kernel void pressure_solve(
          __global float *pressure,
          __global float *pressure_prev,
          __global float *divergence,
         // int i, int j, int k,
          int3 n,
          float dt)
{
  int id = get_global_id(0);
  int slice_size = NX*NY;
  int row_size = NX;
  int k = id / slice_size;
  int j = (id - k*slice_size) / row_size;
  int i = id - j*row_size - k*slice_size;

  // jacobi solver
  float p = -get_data(divergence,i,j,k);
  float a = get_data(pressure,i-1, j, k);
  float b = get_data(pressure,i+1, j, k);
  float c = get_data(pressure,i, j+1, k);
  float d = get_data(pressure,i, j-1, k);
  float e = get_data(pressure,i, j, k-1);
  float f = get_data(pressure,i, j, k+1);
  float v = (p+(a+b+c+d+e+f))/6.0f;

  pressure[IX(i,j,k)] = v;

}

__kernel void pressure_apply(__global float *u,
                    __global float *v,
                    __global float *w,
                    __global float *pressure,
                    //int i, int j, int k,
                    int3 n,
                    float dt)
{
  int id = get_global_id(0);
  int slice_size = NX*NY;
  int row_size = NX;
  int k = id / slice_size;
  int j = (id - k*slice_size) / row_size;
  int i = id - j*row_size - k*slice_size;

//  int lid = get_local_id(0);
//  int local_slice_size = BLOCK_SIZE*BLOCK_SIZE;
//  int local_row_size = BLOCK_SIZE;
//  int lk = lid / local_slice_size;
//  int lj = (lid - lk*local_slice_size) / local_row_size;
//  int li = lid - lj*local_row_size - lk*local_slice_size;
//
//
//  //Put stuff into local memory
//  local float local_pressure[(BLOCK_SIZE_WITH_PAD)*(BLOCK_SIZE_WITH_PAD)*(BLOCK_SIZE_WITH_PAD)];//Should be 10*10*10 = 1000
//  //Handle normal case
//  int local_index = IXL(li+1, lj+1, lk+1);
//  local_pressure[local_index] = pressure[id];
//
//  //Handle edge cases
//  //The left face
//  if(li == 0){
//    local_pressure[IXL(li, lj+1, lk+1)] = get_data(pressure, i-1,j,k);
//  }
//  //The right face
//  if(li == BLOCK_SIZE-1){
//    local_pressure[IXL(li+2, lj+1, lk+1)] = get_data(pressure, i+1,j,k);
//  }
//  //the top face
//  if(lj == 0){
//    local_pressure[IXL(li+1, lj, lk+1)] = get_data(pressure, i,j-1,k);
//  }
//  //the bottom face
//  if(lj == BLOCK_SIZE-1){
//    local_pressure[IXL(li+1, lj+2, lk+1)] = get_data(pressure, i,j+1,k);
//  }
//  //the front face
//  if(lk == 0){
//    local_pressure[IXL(li+1, lj+1, lk)] = get_data(pressure, i,j,k-1);
//  }
//  //the bottom face
//  if(lk == BLOCK_SIZE-1){
//    local_pressure[IXL(li+1, lj+1, lk+2)] = get_data(pressure, i,j,k+1);
//  }
//
//
//  barrier(CLK_LOCAL_MEM_FENCE);

  // calculate pressure gradient
  float dpdi = 0.5f*(get_data(pressure,i+1, j, k)-get_data(pressure,i-1, j, k));
  float dpdj = 0.5f*(get_data(pressure,i, j+1, k)-get_data(pressure,i, j-1, k));
  float dpdk = 0.5f*(get_data(pressure,i, j, k+1)-get_data(pressure,i, j, k-1));

//  float dpdi = 0.5f*(get_data_local(local_pressure,li+2, lj+1, lk+1)-get_data_local(local_pressure,li, lj+1, lk+1));
//  float dpdj = 0.5f*(get_data_local(local_pressure,li+1, lj+2, lk+1)-get_data_local(local_pressure,li+1, lj, lk+1));
//  float dpdk = 0.5f*(get_data_local(local_pressure,li+1, lj+1, lk+2)-get_data_local(local_pressure,li+1, lj+1, lk));

  u[IX(i, j, k)] -=  dpdi;
  v[IX(i, j, k)] -=  dpdj;
  w[IX(i, j, k)] -=  dpdk;
}

#define WRAP_BOUNDS 0
#define IX(i,j,k) ((i) + ((j)*(NX)) + ((k)*(NX)*(NY)))
#define IXL(i,j,k) ((i) + ((j)*(BLOCK_SIZE_WITH_PAD)) + ((k)*(BLOCK_SIZE_WITH_PAD)*(BLOCK_SIZE_WITH_PAD)))
#define LERP(a,b,t) (((1.0)-(t))*(a) + ((t)*(b)))

int mod_int (int a, int b)
{
  if(b < 0) //you can check for b == 0 separately and do what you want
    return mod_int(-a, -b);
  int ret = a % b;
  if(ret < 0)
    ret+=b;
  return ret;
}

float get_data(__global float * x, int i, int j, int k)
{
  //If I basically have a 2D grid then the 3 way check gives bad results
  //if(i < 0 || i >= NX || j < 0 || j >= NY || k < 0 || k >= NZ)
  //if(i < 0 || i >= NX || j < 0 || j >= NY)
  //{
  //	return 0.0f;
  //}

  i = clamp(i,0,NX-1);
  j = clamp(j,0,NY-1);
  k = clamp(k,0,NZ-1);

  return x[IX(i,j,k)];
}

float get_data_local(__local float * x, int i, int j, int k)
{
  i = clamp(i,0,BLOCK_SIZE_WITH_PAD-1);
  j = clamp(j,0,BLOCK_SIZE_WITH_PAD-1);
  k = clamp(k,0,BLOCK_SIZE_WITH_PAD-1);

  return x[IXL(i,j,k)];
}

float get_interpolated_value(
      __global float * x,
      float3 pos,
      float h)
{
   float3 ph = pos/h;
	//The grid world pos is 0-1.
   int3 idx0 = {convert_int(ph.x), convert_int(ph.y), convert_int(ph.z)};
   int3 idx1 = {
            convert_int(clamp(idx0.x + 1, 0,NX-1)),
	          convert_int(clamp(idx0.y + 1, 0,NY-1)),
            convert_int(clamp(idx0.z + 1, 0,NZ-1))
            };

	//Calculate t per component
   //float it,jt,kt;
   float3 t = {
            pos.x - idx0.x*h,
            pos.y - idx0.y*h,
            pos.z - idx0.z*h
            };

	//assert (t.x < 1.0 && t.x >= 0);
	//assert (t.y < 1.0 && t.y >= 0);
	//assert (t.z < 1.0 && t.z >= 0);

	// Assume a cube wt.xh 8 points
	//Front face
	//Top Front Lerp
	float xFrontLeftTop = x[IX(idx0.x,idx1.y,idx0.z)];
	float xFrontRightTop = x[IX(idx1.x,idx1.y,idx0.z)];
	float xFrontTopInterp = mix(xFrontLeftTop, xFrontRightTop, t.x);
	//Bottom Front Lerp
	float xFrontLeftBottom = x[IX(idx0.x,idx0.y,idx0.z)];
	float xFrontRightBottom = x[IX(idx1.x,idx0.y,idx0.z)];
	float xFrontBottomInterp = mix(xFrontLeftBottom, xFrontRightBottom, t.x);

	//Back face
	//Top Back Lerp
	float xBackLeftTop = x[IX(idx0.x,idx1.y,idx1.z)];
	float xBackRightTop = x[IX(idx1.x,idx1.y,idx1.z)];
	float xBackTopInterp = mix(xBackLeftTop, xBackRightTop, t.x);
	//Bottom Back Lerp
	float xBackLeftBottom = x[IX(idx0.x,idx0.y,idx1.z)];
	float xBackRightBottom = x[IX(idx1.x,idx0.y,idx1.z)];
	float xBackBottomInterp = mix(xBackLeftBottom, xBackRightBottom, t.x);

	//Now get middle of front -The bilinear interp of the front face
	float xBiLerpFront = mix(xFrontBottomInterp, xFrontTopInterp,t.y);

	//Now get middle of back -The bilinear interp of the back face
	float xBiLerpBack = mix(xBackBottomInterp, xBackTopInterp, t.y);

	//Now get the interpolated point between the points calculated in
   //the front and back faces - The trilinear interp part
	float xTriLerp = mix(xBiLerpFront, xBiLerpBack, t.z);

	return xTriLerp;
}

__kernel void advect_forward_euler(
      const float delta_time,
      int3  dims,
      const float H,
      __global float *q,
      __global float * q_prev,
      __global float * u_prev,
      __global float * v_prev,
      __global float * w_prev
//      __global float4 * debugData1,
//      __global float4 * debugData2,
//      __global float4 * debugData3
                                   )
{
  int id = get_global_id(0);

  float dt = -delta_time*NX;

  int slice_size = NX*NY;
  int row_size = NX;
  int k = id / slice_size;
  int j = (id - k*slice_size) / row_size;
  int i = id - j*row_size - k*slice_size;

  float3 pos = {i*H, j*H, k*H};

  //debugData1[id] = pos.xyzx;

  float3 orig_vel = {
           u_prev[IX(i,j,k)],
           v_prev[IX(i,j,k)],
           w_prev[IX(i,j,k)]
  };

  //debugData1[id] = orig_vel.xyzx;

  float3 new_pos = {
           pos.x+(dt*orig_vel.x),
           pos.y+(dt*orig_vel.y),
           pos.z+(dt*orig_vel.z)
  };

  //debugData1[id] = new_pos.xyzx;

#if !WRAP_BOUNDS
	new_pos.x   = clamp(new_pos.x,0.0f,NX-1.0f);
	new_pos.y   = clamp(new_pos.y,0.0f,NY-1.0f);
	new_pos.z   = clamp(new_pos.z,0.0f,NZ-1.0f);
#endif

  //Have to interpolate at new point
	float traced_q;
  traced_q = get_interpolated_value( q_prev, new_pos, H);

  q[id] = traced_q;

}

__kernel void advectRK2(
            const float delta_time,
            int3  dims,
            const float H,
            __global float *q,
            __global float * q_prev,
            __global float * u_prev,
            __global float * v_prev,
            __global float * w_prev
//            __global float4 * debugData1,
//            __global float4 * debugData2,
//            __global float4 * debugData3
                        )
{
  int id = get_global_id(0);

	float dt = -delta_time*NX;

	//FOR_EACH_FACE
	//{
  int slice_size = NX*NY;
  int row_size = NX;
  int k = id / slice_size;
  int j = (id - k*slice_size) / row_size;
  int i = id - j*row_size - k*slice_size;

  float3 pos = {i*H, j*H, k*H};
  float3 orig_vel = {u_prev[IX(i,j,k)],v_prev[IX(i,j,k)],w_prev[IX(i,j,k)]};

  //RK2
  // What is u(x)?  value(such as velocity) at x i guess
  //y = x + dt*u(x + (dt/2)*u(x))

  //backtrace based upon current velocity at cell center.
  float halfDT = 0.5*dt;
  float3 halfway_position = {
    pos.x+(halfDT*orig_vel.x),
    pos.y+(halfDT*orig_vel.y),
    pos.z+(halfDT*orig_vel.z)
  };

#if !WRAP_BOUNDS
  halfway_position.x  = clamp(halfway_position.x,0.0f,NX-1.0f);
  halfway_position.y  = clamp(halfway_position.y,0.0f,NY-1.0f);
  halfway_position.z  = clamp(halfway_position.z,0.0f,NZ-1.0f);
#endif

  float3 halfway_vel;
  halfway_vel.x = get_interpolated_value(u_prev, halfway_position,H);
  halfway_vel.y = get_interpolated_value(v_prev, halfway_position,H);
  halfway_vel.z = get_interpolated_value(w_prev, halfway_position,H);

  float3 backtraced_position;
  backtraced_position.x  = pos.x + dt*halfway_vel.x;
  backtraced_position.y  = pos.y + dt*halfway_vel.y;
  backtraced_position.z  = pos.z + dt*halfway_vel.z;

#if !WRAP_BOUNDS
  backtraced_position.x  = clamp(backtraced_position.x,0.0f,NX-1.0f);
  backtraced_position.y  = clamp(backtraced_position.y,0.0f,NY-1.0f);
  backtraced_position.z  = clamp(backtraced_position.z,0.0f,NZ-1.0f);
#endif

  //Have to interpolate at new point
  float traced_q;
  traced_q = get_interpolated_value(q_prev, backtraced_position,H);

  //Has to be set on u
  q[IX(i,j,k)] = traced_q;

	//}
}

__kernel void advect_velocity_RK2(
                         const float delta_time,
                         int3  dims,
                         const float H,
                         __global float * u,
                         __global float * v,
                         __global float * w,
                         __global float * u_prev,
                         __global float * v_prev,
                         __global float * w_prev
//                         __global float4 * debugData1,
//                         __global float4 * debugData2,
//                         __global float4 * debugData3
                                  )

{
  int id = get_global_id(0);

	float dt = -delta_time*NX;

  int slice_size = NX*NY;
  int row_size = NX;
  int k = id / slice_size;
  int j = (id - k*slice_size) / row_size;
  int i = id - j*row_size - k*slice_size;

  float3 pos = {i*H,j*H,k*H};
  float3 orig_vel = {u_prev[IX(i,j,k)],v_prev[IX(i,j,k)],w_prev[IX(i,j,k)]};

  //RK2
  // What is u(x)?  value(such as velocity) at x i guess
  //y = x + dt*u(x + (dt/2)*u(x))

  //backtrace based upon current velocity at cell center.
  float halfDT = 0.5*dt;
  float3 halfway_position = {
    pos.x+(halfDT*orig_vel.x),
    pos.y+(halfDT*orig_vel.y),
    pos.z+(halfDT*orig_vel.z)
  };

#if !WRAP_BOUNDS
  halfway_position.x  = clamp(halfway_position.x,0.0f,NX-1.0f);
  halfway_position.y  = clamp(halfway_position.y,0.0f,NY-1.0f);
  halfway_position.z  = clamp(halfway_position.z,0.0f,NZ-1.0f);
#endif

  float3 halfway_vel;
  halfway_vel.x = get_interpolated_value(u_prev, halfway_position,H);
  halfway_vel.y = get_interpolated_value(v_prev, halfway_position,H);
  halfway_vel.z = get_interpolated_value(w_prev, halfway_position,H);

  float3 backtraced_position;
  backtraced_position.x  = pos.x + dt*halfway_vel.x;
  backtraced_position.y  = pos.y + dt*halfway_vel.y;
  backtraced_position.z  = pos.z + dt*halfway_vel.z;

#if !WRAP_BOUNDS
  backtraced_position.x  = clamp(backtraced_position.x,0.0f,NX-1.0f);
  backtraced_position.y  = clamp(backtraced_position.y,0.0f,NY-1.0f);
  backtraced_position.z  = clamp(backtraced_position.z,0.0f,NZ-1.0f);
#endif

  //Have to interpolate at new point
  float3 traced_velocity;
  traced_velocity.x = get_interpolated_value(u_prev, backtraced_position,H);
  traced_velocity.y = get_interpolated_value(v_prev, backtraced_position,H);
  traced_velocity.z = get_interpolated_value(w_prev, backtraced_position,H);

  //Has to be set on u
  u[IX(i,j,k)] = traced_velocity.x;
  v[IX(i,j,k)] = traced_velocity.y;
  w[IX(i,j,k)] = traced_velocity.z;

}

__kernel void advect_velocity_forward_euler(
                                  const float delta_time,
                                  int3  dims,
                                  const float H,
                                  __global float * u,
                                  __global float * v,
                                  __global float * w,
                                  __global float * u_prev,
                                  __global float * v_prev,
                                  __global float * w_prev
//                                  __global float4 * debugData1,
//                                  __global float4 * debugData2,
//                                  __global float4 * debugData3
                                            )

{
  int id = get_global_id(0);
  int slice_size = NX*NY;
  int row_size = NX;
  int k = id / slice_size;
  int j = (id - k*slice_size) / row_size;
  int i = id - j*row_size - k*slice_size;

  float dt =  -delta_time * NX;

  float3 pos = {i*H,j*H,k*H};
  float3 orig_vel = {u_prev[IX(i,j,k)],v_prev[IX(i,j,k)],w_prev[IX(i,j,k)]};

  float3 new_pos = {
    pos.x+(dt*orig_vel.x),
    pos.y+(dt*orig_vel.y),
    pos.z+(dt*orig_vel.z)
  };

#if !WRAP_BOUNDS
  new_pos.x  = clamp(new_pos.x,0.0f,NX-1.0f);
  new_pos.y  = clamp(new_pos.y,0.0f,NY-1.0f);
  new_pos.z  = clamp(new_pos.z,0.0f,NZ-1.0f);
#endif

  float3 new_vel;
  new_vel.x = get_interpolated_value(u_prev, new_pos,H);
  new_vel.y = get_interpolated_value(v_prev, new_pos,H);
  new_vel.z = get_interpolated_value(w_prev, new_pos,H);

  //Has to be set on u
  u[IX(i,j,k)] = new_vel.x;
  v[IX(i,j,k)] = new_vel.y;
  w[IX(i,j,k)] = new_vel.z;

//  if(id == 112)
//  {
//    printf("dt = %3.2f\n",dt);
//    printf("NX = %d\n",NX);
//    printf("pos = %3.2f,%3.2f,%3.2f\n",pos.x,pos.y,pos.z);
//    printf("new_pos = %3.2f,%3.2f,%3.2f\n",new_pos.x,new_pos.y,new_pos.z);
//
//  }
//
}

float4 safe_normalize(float4 p)
{
  float4 v = p;
  float l = length(v);
  if(l > 0.0f)
  {
    v = normalize(v);
  }
  else
  {
    v.xyzw =  0.0f;
  }
  return v;
}

float4 get_curl(
                __global float * u,
                __global float * v,
                __global float * w,
                int i, int j, int k)
{
	float dwdj = 0.5f*(get_data(w, i, j+1, k) - get_data(w,i, j-1, k));
	float dwdi = 0.5f*(get_data(w, i+1, j, k) - get_data(w,i-1, j, k));

	float dudk = 0.5f*(get_data(u, i, j, k+1)-get_data(u, i, j, k-1));
	float dudj = 0.5f*(get_data(u, i, j+1, k)-get_data(u, i, j-1, k));

	float dvdk = 0.5f*(get_data(v, i, j, k+1)-get_data(v, i, j, k-1));
	float dvdi = 0.5f*(get_data(v, i+1, j, k)-get_data(v, i-1, j, k));

  float4 out = {dwdj-dvdk, dudk-dwdi, dvdi-dudj,0.0f};
  return out;
}

__kernel void vorticity_confinement(__global float *u,
                                    __global float *v,
                                    __global float* w,
                                    __global float * u_prev,
                                    __global float * v_prev,
                                    __global float * w_prev,
                                    int3 n,
                                    float e,
                                    float dt)
{
  int id = get_global_id(0);
  int slice_size = NX*NY;
  int row_size = NX;
  int k = id / slice_size;
  int j = (id - k*slice_size) / row_size;
  int i = id - j*row_size - k*slice_size;

  //if(i < 1 || j < 1 || (NZ > 1 && k < 1) || i > NX -1 || j > NY-1 || (NZ > 1 && k > NZ-1) || (NZ == 1 && k > 1))
  if(i < 1 || j < 1 || k < 0 || i >= NX -1 || j >= NY-1 ||  k > NZ )
    return;

	float4 curl;
  float4 curl_iplus1;
  float4 curl_iminus1;
  float4 curl_jplus1;
  float4 curl_jminus1;
  float4 curl_kplus1;
  float4 curl_kminus1;

  float4 norm;
  float4 f;

    // calculate gradient of curl magnitude
    curl_iplus1 = get_curl(u_prev,v_prev, w_prev, i+1, j, k);
    curl_iminus1= get_curl(u_prev,v_prev, w_prev, i-1, j, k);

    curl_jplus1 = get_curl(u_prev,v_prev, w_prev, i, j+1, k);
    curl_jminus1= get_curl(u_prev,v_prev, w_prev, i, j-1, k);

    curl_kplus1 = get_curl(u_prev,v_prev, w_prev, i, j, k+1);
    curl_kminus1 = get_curl(u_prev,v_prev, w_prev, i, j, k-1);

    float dcdi = 0.5f*(length(curl_iplus1) - length(curl_iminus1));
    float dcdj = 0.5f*(length(curl_jplus1) - length(curl_jminus1));
    float dcdk = 0.5f*(length(curl_kplus1) - length(curl_kminus1));

    norm.x = dcdi;
    norm.y = dcdj;
    norm.z = dcdk;
    norm.w = 0.0f;

    norm = safe_normalize(norm);

    curl = get_curl(u_prev,v_prev, w_prev, i, j, k);

    //float e = 0.5f;

    f = cross(norm, curl);

    u[IX(i,j,k)] += f.x * e * dt;
    v[IX(i,j,k)] += f.y * e * dt;
    w[IX(i,j,k)] += f.z * e * dt;

}

__kernel void calculate_divergence(
            __global float *divergence,
            __global float *u,
            __global float *v,
            __global float *w,
           // int i, int j, int k,
            int3 n,
            float dt )
{
	{
    int id = get_global_id(0);
    int slice_size = NX*NY;
    int row_size = NX;
    int k = id / slice_size;
    int j = (id - k*slice_size) / row_size;
    int i = id - j*row_size - k*slice_size;

		float du = get_data(u,i+1,j,k) - get_data(u,i-1,j,k);
		float dv = get_data(v,i,j+1,k) - get_data(v,i,j-1,k);
		float dw = get_data(w,i,j,k+1) - get_data(w,i,j,k-1);
		float div = 0.5*(du + dv + dw);

		divergence[IX(i,j,k)] = div;

    barrier(CLK_GLOBAL_MEM_FENCE);
	}
}

__kernel void zero_pressure( __global float *pressure)
{
  int id = get_global_id(0);

	pressure[id]  = 0.0f;

}

__kernel void vector_dot_product(
                                    __global float* a,
                                    __global float* b,
                                    int n) {

}

__kernel void laplacian_mtx_vec_mult(
                                     __global float *out,
                                     __global float* x,
                                     int3 n) {

  int id = get_global_id(0);
  int slice_size = NX*NY;
  int row_size = NX;
  int k = id / slice_size;
  int j = (id - k*slice_size) / row_size;
  int i = id - j*row_size - k*slice_size;

  float sum = 0.0f;
  sum += -6.0f * x[id];
  sum += get_data(x,i-1,j,k);
  sum += get_data(x,i+1,j,k);
  sum += get_data(x,i,j-1,k);
  sum += get_data(x,i,j+1,k);
  sum += get_data(x,i,j,k-1);
  sum += get_data(x,i,j,k+1);

  out[id] = sum;
}

__kernel void pressure_solve(
          __global float *pressure,
          __global float *pressure_prev,
          __global float *divergence,
         // int i, int j, int k,
          int3 n,
          float dt)
{
  int id = get_global_id(0);
  int slice_size = NX*NY;
  int row_size = NX;
  int k = id / slice_size;
  int j = (id - k*slice_size) / row_size;
  int i = id - j*row_size - k*slice_size;

  // jacobi solver
  float p = -get_data(divergence,i,j,k);
  float a = get_data(pressure,i-1, j, k);
  float b = get_data(pressure,i+1, j, k);
  float c = get_data(pressure,i, j+1, k);
  float d = get_data(pressure,i, j-1, k);
  float e = get_data(pressure,i, j, k-1);
  float f = get_data(pressure,i, j, k+1);
  float v = (p+(a+b+c+d+e+f))/6.0f;

  pressure[IX(i,j,k)] = v;

}

__kernel void pressure_apply(__global float *u,
                    __global float *v,
                    __global float *w,
                    __global float *pressure,
                    //int i, int j, int k,
                    int3 n,
                    float dt)
{
  int id = get_global_id(0);
  int slice_size = NX*NY;
  int row_size = NX;
  int k = id / slice_size;
  int j = (id - k*slice_size) / row_size;
  int i = id - j*row_size - k*slice_size;

//  int lid = get_local_id(0);
//  int local_slice_size = BLOCK_SIZE*BLOCK_SIZE;
//  int local_row_size = BLOCK_SIZE;
//  int lk = lid / local_slice_size;
//  int lj = (lid - lk*local_slice_size) / local_row_size;
//  int li = lid - lj*local_row_size - lk*local_slice_size;
//
//
//  //Put stuff into local memory
//  local float local_pressure[(BLOCK_SIZE_WITH_PAD)*(BLOCK_SIZE_WITH_PAD)*(BLOCK_SIZE_WITH_PAD)];//Should be 10*10*10 = 1000
//  //Handle normal case
//  int local_index = IXL(li+1, lj+1, lk+1);
//  local_pressure[local_index] = pressure[id];
//
//  //Handle edge cases
//  //The left face
//  if(li == 0){
//    local_pressure[IXL(li, lj+1, lk+1)] = get_data(pressure, i-1,j,k);
//  }
//  //The right face
//  if(li == BLOCK_SIZE-1){
//    local_pressure[IXL(li+2, lj+1, lk+1)] = get_data(pressure, i+1,j,k);
//  }
//  //the top face
//  if(lj == 0){
//    local_pressure[IXL(li+1, lj, lk+1)] = get_data(pressure, i,j-1,k);
//  }
//  //the bottom face
//  if(lj == BLOCK_SIZE-1){
//    local_pressure[IXL(li+1, lj+2, lk+1)] = get_data(pressure, i,j+1,k);
//  }
//  //the front face
//  if(lk == 0){
//    local_pressure[IXL(li+1, lj+1, lk)] = get_data(pressure, i,j,k-1);
//  }
//  //the bottom face
//  if(lk == BLOCK_SIZE-1){
//    local_pressure[IXL(li+1, lj+1, lk+2)] = get_data(pressure, i,j,k+1);
//  }
//
//
//  barrier(CLK_LOCAL_MEM_FENCE);

  // calculate pressure gradient
  float dpdi = 0.5f*(get_data(pressure,i+1, j, k)-get_data(pressure,i-1, j, k));
  float dpdj = 0.5f*(get_data(pressure,i, j+1, k)-get_data(pressure,i, j-1, k));
  float dpdk = 0.5f*(get_data(pressure,i, j, k+1)-get_data(pressure,i, j, k-1));

//  float dpdi = 0.5f*(get_data_local(local_pressure,li+2, lj+1, lk+1)-get_data_local(local_pressure,li, lj+1, lk+1));
//  float dpdj = 0.5f*(get_data_local(local_pressure,li+1, lj+2, lk+1)-get_data_local(local_pressure,li+1, lj, lk+1));
//  float dpdk = 0.5f*(get_data_local(local_pressure,li+1, lj+1, lk+2)-get_data_local(local_pressure,li+1, lj+1, lk));

  u[IX(i, j, k)] -=  dpdi;
  v[IX(i, j, k)] -=  dpdj;
  w[IX(i, j, k)] -=  dpdk;
}