Indexing cleanup.

Indexing cleanup.

#pragma OPENCL EXTENSION cl_khr_fp64 : enable

__kernel
void matvec_single(__global const double *A, __global const double *x,
                   __global double *b, int n) {

  int gid = get_global_id(0);
  const int stride = get_global_size(0);

  double sum;
  while(gid<n) {

    sum = 0.0;
    for(int i=0; i<n; ++i)
      sum += A[gid*n+i]*x[i];
    b[gid] = sum;

    gid += stride;

  }

}

__kernel
void matvec_tile(__global const double *A, __global const double *x,
                 __global double *b, int n, int tile_size) {

  // Assume n%tile_size==0

  // gid is i_outer
  int gid = get_global_id(0)*tile_size;
  const int stride = get_global_size(0)*tile_size;
  const int T = tile_size;

  double sum;
  while(gid<n) {

    for(int j_outer=0; j_outer<n/T; ++j_outer) {
      for(int i_inner=0; i_inner<T; ++i_inner) {

          sum = 0.0;
          for(int j_inner=0; j_inner<T; ++j_inner)
            sum += A[(gid+i_inner)*n+j_outer*T+j_inner]*x[j_outer*T+j_inner];

          b[gid+i_inner] += sum;

      }
    }

    gid += stride;

  }

}

// A is nxn, M is nxk, B is nxk
__kernel
void matmat_single(__global const double *A, __global const double *M,
                   __global double *B, int n, int k) {

  int gid = get_global_id(0);
  const int stride = get_global_size(0);

  double sum;
  while(gid<n) {

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

      sum = 0.0;
      for(int i=0; i<n; ++i)
        sum += A[gid*n+i]*M[k*i+j];

      B[gid*k+j] = sum;

    }

    gid += stride;

  }

}

// A is nxn, M is nxk, B is nxk
__kernel
void matmat_tile(__global const double *A, __global const double *M,
                 __global double *B, int n, int k, int tile_size) {

  // Assume n%tile_size==0

  // gid is i_outer
  int gid = get_global_id(0)*tile_size;
  const int stride = get_global_size(0)*tile_size;
  const int T = tile_size;

  double sum;
  while(gid<n) {

    for(int j_outer=0; j_outer<n/T; ++j_outer) {
      for(int k_outer=0; k_outer<k/T; ++k_outer) {
        for(int i_inner=0; i_inner<T; ++i_inner) {
          for(int k_inner=0; k_inner<T; ++k_inner) {

            sum = 0.0;
            for(int j_inner=0; j_inner<T; ++j_inner)
              sum += A[(gid+i_inner)*n+j_outer*T+j_inner]*M[(j_outer*T+j_inner)*k+k_outer*T+k_inner];

            B[(gid+i_inner)*k+k_outer*T+k_inner] += sum;

          }
        }

      }
    }

    gid += stride;

  }

}

// A is nxn, M is nxk, B is nxk
__kernel
void tensor_IIA_single(__global const double *A, __global const double *M,
                       __global double *B, int n) {

  int gid = get_global_id(0);
  const int stride = get_global_size(0);

  double sum;
  while(gid<n) {

    for(int k=0; k<n; ++k) {
      for(int j=0; j<n; ++j) {

        sum = 0.0;
        for(int i=0; i<n; ++i)
          sum += A[n*gid+i]*M[k*n*n+n*j+i];

        B[k*n*n+n*j+gid] = sum;

      }

    }

    gid += stride;

  }

}

// A is nxn, M is nxk, B is nxk
__kernel
void tensor_IAI_single(__global const double *A, __global const double *M,
                       __global double *B, int n) {

  int gid = get_global_id(0);
  const int stride = get_global_size(0);

  double sum;
  while(gid<n) {

    for(int k=0; k<n; ++k) {
      for(int j=0; j<n; ++j) {

        sum = 0.0;
        for(int i=0; i<n; ++i)
          sum += A[n*gid+i]*M[k*n*n+n*i+j];

        B[k*n*n+n*gid+j] = sum;

      }

    }

    gid += stride;

  }

}

// A is nxn, M is nxk, B is nxk
__kernel
void tensor_AII_single(__global const double *A, __global const double *M,
                       __global double *B, int n) {

  int gid = get_global_id(0);
  const int stride = get_global_size(0);

  double sum;
  while(gid<n) {

    for(int k=0; k<n; ++k) {
      for(int j=0; j<n; ++j) {

        sum = 0.0;
        for(int i=0; i<n; ++i)
          sum += A[n*gid+i]*M[i*n*n+n*k+j];

        B[gid*n*n+n*k+j] = sum;

      }

    }

    gid += stride;

  }

}

__kernel
void tensor_tile(__global const double *A, __global const double *M,
                 __global double *B, int n, int tile_size, int imat) {

  // Assume n%tile_size==0

  // gid is i_outer*T
  int gid = get_global_id(0)*tile_size;
  const int stride = get_global_size(0)*tile_size;
  const int T = tile_size;

  int ni, nj, nk, nm;
  if(imat==0) {
    ni = 1;
    nj = 1;
    nk = n*n;
    nm = n;
  }
  else if(imat==1) {
    ni = n;
    nj = n;
    nk = 1;
    nm = n*n;
  }
  else if(imat==2) {
    ni = n*n;
    nj = n*n;
    nk = 1;
    nm = n;
  }

  int i_ind, j_ind, k_ind, m_ind;
  double sum;
  while(gid<n) {

    for(int m_outer=0; m_outer<n/T; ++m_outer) {
      for(int j_outer=0; j_outer<n/T; ++j_outer) {
        for(int k_outer=0; k_outer<n/T; ++k_outer) {

          for(int m_inner=0; m_inner<T; ++m_inner) { m_ind = m_outer*T+m_inner;
            for(int i_inner=0; i_inner<T; ++i_inner) { i_ind = gid+i_inner;
              for(int k_inner=0; k_inner<T; ++k_inner) { k_ind = k_outer*T+k_inner;

                sum = 0.0;
                for(int j_inner=0; j_inner<T; ++j_inner) { j_ind = j_outer*T+j_inner;
                  sum += A[i_ind*n+j_ind]*M[m_ind*nm+j_ind*nj+k_ind*nk];
                }

                B[m_ind*nm+i_ind*ni+k_ind*nk] += sum;

              }
            }

          }
        }
      }
    }

    gid += stride;

  }

}

// __kernel
// void tensor_IIA_tile(__global const double *A, __global const double *M,
//                      __global double *B, int n, int tile_size) {

//   // Assume n%tile_size==0

//   // gid is i_outer*T
//   int gid = get_global_id(0)*tile_size;
//   const int stride = get_global_size(0)*tile_size;
//   const int T = tile_size;

//   double sum;
//   while(gid<n) {

//     for(int m=0; m<n; ++m) {

//       for(int j_outer=0; j_outer<n/T; ++j_outer) {
//         for(int k_outer=0; k_outer<n/T; ++k_outer) {
//           for(int i_inner=0; i_inner<T; ++i_inner) {
//             for(int k_inner=0; k_inner<T; ++k_inner) {

//               sum = 0.0;
//               for(int j_inner=0; j_inner<T; ++j_inner)
//                 sum += A[(gid+i_inner)*n+j_outer*T+j_inner]*M[m*n+
//                                                               (j_outer*T+j_inner)+
//                                                               (k_outer*T+k_inner)*n*n];

//               B[m*n+(gid+i_inner)+(k_outer*T+k_inner)*n*n] += sum;

//             }
//           }

//         }
//       }

//     }

//     gid += stride;

//   }

// }

// __kernel
// void tensor_IAI_tile(__global const double *A, __global const double *M,
//                      __global double *B, int n, int tile_size) {

//   // Assume n%tile_size==0

//   // gid is i_outer
//   int gid = get_global_id(0)*tile_size;
//   const int stride = get_global_size(0)*tile_size;
//   const int T = tile_size;

//   double sum;
//   while(gid<n) {

//     for(int m=0; m<n; ++m) {

//       for(int j_outer=0; j_outer<n/T; ++j_outer) {
//         for(int k_outer=0; k_outer<n/T; ++k_outer) {
//           for(int i_inner=0; i_inner<T; ++i_inner) {
//             for(int k_inner=0; k_inner<T; ++k_inner) {

//               sum = 0.0;
//               for(int j_inner=0; j_inner<T; ++j_inner)
//                 sum += A[(gid+i_inner)*n+j_outer*T+j_inner]*M[(j_outer*T+j_inner)*n+
//                                                               k_outer*T+k_inner+
//                                                               m*n*n];

//               B[(gid+i_inner)*n+k_outer*T+k_inner+m*n*n] += sum;

//             }
//           }

//         }
//       }

//     }

//     gid += stride;

//   }

// }

// __kernel
// void tensor_AII_tile(__global const double *A, __global const double *M,
//                      __global double *B, int n, int tile_size) {

//   // Assume n%tile_size==0

//   // gid is i_outer
//   int gid = get_global_id(0)*tile_size;
//   const int stride = get_global_size(0)*tile_size;
//   const int T = tile_size;

//   double sum;
//   while(gid<n) {

//     for(int m=0; m<n; ++m) {

//       for(int j_outer=0; j_outer<n/T; ++j_outer) {
//         for(int k_outer=0; k_outer<n/T; ++k_outer) {
//           for(int i_inner=0; i_inner<T; ++i_inner) {
//             for(int k_inner=0; k_inner<T; ++k_inner) {

//               sum = 0.0;
//               for(int j_inner=0; j_inner<T; ++j_inner)
//                 sum += A[(gid+i_inner)*n+j_outer*T+j_inner]*M[m*n+
//                                                               (j_outer*T+j_inner)*n*n+
//                                                               (k_outer*T+k_inner)];

//               B[m*n+(gid+i_inner)*n*n+(k_outer*T+k_inner)] += sum;

//             }
//           }

//         }
//       }

//     }

//     gid += stride;

//   }

// }

#pragma OPENCL EXTENSION cl_khr_fp64 : enable

__kernel
void matvec_single(__global const double *A, __global const double *x,
                   __global double *b, int n) {

  int gid = get_global_id(0);
  const int stride = get_global_size(0);

  double sum;
  while(gid<n) {

    sum = 0.0;
    for(int i=0; i<n; ++i)
      sum += A[gid*n+i]*x[i];
    b[gid] = sum;

    gid += stride;

  }

}

__kernel
void matvec_tile(__global const double *A, __global const double *x,
                 __global double *b, int n, int tile_size) {

  // Assume n%tile_size==0

  // gid is i_outer
  int gid = get_global_id(0)*tile_size;
  const int stride = get_global_size(0)*tile_size;
  const int T = tile_size;

  double sum;
  while(gid<n) {

    for(int j_outer=0; j_outer<n/T; ++j_outer) {
      for(int i_inner=0; i_inner<T; ++i_inner) {

          sum = 0.0;
          for(int j_inner=0; j_inner<T; ++j_inner)
            sum += A[(gid+i_inner)*n+j_outer*T+j_inner]*x[j_outer*T+j_inner];

          b[gid+i_inner] += sum;

      }
    }

    gid += stride;

  }

}

// A is nxn, M is nxk, B is nxk
__kernel
void matmat_single(__global const double *A, __global const double *M,
                   __global double *B, int n, int k) {

  int gid = get_global_id(0);
  const int stride = get_global_size(0);

  double sum;
  while(gid<n) {

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

      sum = 0.0;
      for(int i=0; i<n; ++i)
        sum += A[gid*n+i]*M[k*i+j];

      B[gid*k+j] = sum;

    }

    gid += stride;

  }

}

// A is nxn, M is nxk, B is nxk
__kernel
void matmat_tile(__global const double *A, __global const double *M,
                 __global double *B, int n, int k, int tile_size) {

  // Assume n%tile_size==0

  // gid is i_outer
  int gid = get_global_id(0)*tile_size;
  const int stride = get_global_size(0)*tile_size;
  const int T = tile_size;

  double sum;
  while(gid<n) {

    for(int j_outer=0; j_outer<n/T; ++j_outer) {
      for(int k_outer=0; k_outer<k/T; ++k_outer) {
        for(int i_inner=0; i_inner<T; ++i_inner) {
          for(int k_inner=0; k_inner<T; ++k_inner) {

            sum = 0.0;
            for(int j_inner=0; j_inner<T; ++j_inner)
              sum += A[(gid+i_inner)*n+j_outer*T+j_inner]*M[(j_outer*T+j_inner)*k+k_outer*T+k_inner];

            B[(gid+i_inner)*k+k_outer*T+k_inner] += sum;

          }
        }

      }
    }

    gid += stride;

  }

}

// A is nxn, M is nxk, B is nxk
__kernel
void tensor_IIA_single(__global const double *A, __global const double *M,
                       __global double *B, int n) {

  int gid = get_global_id(0);
  const int stride = get_global_size(0);

  double sum;
  while(gid<n) {

    for(int k=0; k<n; ++k) {
      for(int j=0; j<n; ++j) {

        sum = 0.0;
        for(int i=0; i<n; ++i)
          sum += A[n*gid+i]*M[k*n*n+n*j+i];

        B[k*n*n+n*j+gid] = sum;

      }

    }

    gid += stride;

  }

}

// A is nxn, M is nxk, B is nxk
__kernel
void tensor_IAI_single(__global const double *A, __global const double *M,
                       __global double *B, int n) {

  int gid = get_global_id(0);
  const int stride = get_global_size(0);

  double sum;
  while(gid<n) {

    for(int k=0; k<n; ++k) {
      for(int j=0; j<n; ++j) {

        sum = 0.0;
        for(int i=0; i<n; ++i)
          sum += A[n*gid+i]*M[k*n*n+n*i+j];

        B[k*n*n+n*gid+j] = sum;

      }

    }

    gid += stride;

  }

}

// A is nxn, M is nxk, B is nxk
__kernel
void tensor_AII_single(__global const double *A, __global const double *M,
                       __global double *B, int n) {

  int gid = get_global_id(0);
  const int stride = get_global_size(0);

  double sum;
  while(gid<n) {

    for(int k=0; k<n; ++k) {
      for(int j=0; j<n; ++j) {

        sum = 0.0;
        for(int i=0; i<n; ++i)
          sum += A[n*gid+i]*M[i*n*n+n*k+j];

        B[gid*n*n+n*k+j] = sum;

      }

    }

    gid += stride;

  }

}

__kernel
void tensor_tile(__global const double *A, __global const double *M,
                 __global double *B, int n, int tile_size, int imat) {

  // Assume n%tile_size==0

  // gid is i_outer*T
  int gid = get_global_id(0)*tile_size;
  const int stride = get_global_size(0)*tile_size;
  const int T = tile_size;

  int ni, nj, nk, nm;
  if(imat==0) {
    ni = 1;
    nj = 1;
    nk = n*n;
    nm = n;
  }
  else if(imat==1) {
    ni = n;
    nj = n;
    nk = 1;
    nm = n*n;
  }
  else if(imat==2) {
    ni = n*n;
    nj = n*n;
    nk = 1;
    nm = n;
  }

  double sum;
  while(gid<n) {

    for(int m_outer=0; m_outer<n/T; ++m_outer) {
      for(int j_outer=0; j_outer<n/T; ++j_outer) {
        for(int k_outer=0; k_outer<n/T; ++k_outer) {

          for(int m_inner=0; m_inner<T; ++m_inner) {
            for(int i_inner=0; i_inner<T; ++i_inner) {
              for(int k_inner=0; k_inner<T; ++k_inner) {

                sum = 0.0;
                for(int j_inner=0; j_inner<T; ++j_inner)
                  sum += A[(gid+i_inner)*n+j_outer*T+j_inner]*M[(m_outer*T+m_inner)*nm+
                                                                (j_outer*T+j_inner)*nj+
                                                                (k_outer*T+k_inner)*nk];

                B[(m_outer*T+m_inner)*nm+(gid+i_inner)*ni+(k_outer*T+k_inner)*nk] += sum;

              }
            }

          }
        }
      }
    }

    gid += stride;

  }

}

// __kernel
// void tensor_IIA_tile(__global const double *A, __global const double *M,
//                      __global double *B, int n, int tile_size) {

//   // Assume n%tile_size==0

//   // gid is i_outer*T
//   int gid = get_global_id(0)*tile_size;
//   const int stride = get_global_size(0)*tile_size;
//   const int T = tile_size;

//   double sum;
//   while(gid<n) {

//     for(int m=0; m<n; ++m) {

//       for(int j_outer=0; j_outer<n/T; ++j_outer) {
//         for(int k_outer=0; k_outer<n/T; ++k_outer) {
//           for(int i_inner=0; i_inner<T; ++i_inner) {
//             for(int k_inner=0; k_inner<T; ++k_inner) {

//               sum = 0.0;
//               for(int j_inner=0; j_inner<T; ++j_inner)
//                 sum += A[(gid+i_inner)*n+j_outer*T+j_inner]*M[m*n+
//                                                               (j_outer*T+j_inner)+
//                                                               (k_outer*T+k_inner)*n*n];

//               B[m*n+(gid+i_inner)+(k_outer*T+k_inner)*n*n] += sum;

//             }
//           }

//         }
//       }

//     }

//     gid += stride;

//   }

// }

// __kernel
// void tensor_IAI_tile(__global const double *A, __global const double *M,
//                      __global double *B, int n, int tile_size) {

//   // Assume n%tile_size==0

//   // gid is i_outer
//   int gid = get_global_id(0)*tile_size;
//   const int stride = get_global_size(0)*tile_size;
//   const int T = tile_size;

//   double sum;
//   while(gid<n) {

//     for(int m=0; m<n; ++m) {

//       for(int j_outer=0; j_outer<n/T; ++j_outer) {
//         for(int k_outer=0; k_outer<n/T; ++k_outer) {
//           for(int i_inner=0; i_inner<T; ++i_inner) {
//             for(int k_inner=0; k_inner<T; ++k_inner) {

//               sum = 0.0;
//               for(int j_inner=0; j_inner<T; ++j_inner)
//                 sum += A[(gid+i_inner)*n+j_outer*T+j_inner]*M[(j_outer*T+j_inner)*n+
//                                                               k_outer*T+k_inner+
//                                                               m*n*n];

//               B[(gid+i_inner)*n+k_outer*T+k_inner+m*n*n] += sum;

//             }
//           }

//         }
//       }

//     }

//     gid += stride;

//   }

// }

// __kernel
// void tensor_AII_tile(__global const double *A, __global const double *M,
//                      __global double *B, int n, int tile_size) {

//   // Assume n%tile_size==0

//   // gid is i_outer
//   int gid = get_global_id(0)*tile_size;
//   const int stride = get_global_size(0)*tile_size;
//   const int T = tile_size;

//   double sum;
//   while(gid<n) {

//     for(int m=0; m<n; ++m) {

//       for(int j_outer=0; j_outer<n/T; ++j_outer) {
//         for(int k_outer=0; k_outer<n/T; ++k_outer) {
//           for(int i_inner=0; i_inner<T; ++i_inner) {
//             for(int k_inner=0; k_inner<T; ++k_inner) {

//               sum = 0.0;
//               for(int j_inner=0; j_inner<T; ++j_inner)
//                 sum += A[(gid+i_inner)*n+j_outer*T+j_inner]*M[m*n+
//                                                               (j_outer*T+j_inner)*n*n+
//                                                               (k_outer*T+k_inner)];

//               B[m*n+(gid+i_inner)*n*n+(k_outer*T+k_inner)] += sum;

//             }
//           }

//         }
//       }

//     }

//     gid += stride;

//   }

// }


Bug fix in OpenCL scan for Intel.

Bug fix in OpenCL scan for Intel.

#if Ti == double
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
#endif

__kernel
void scan_first_kernel(__global To *oData, KParam oInfo,
                       __global To *tData, KParam tInfo,
                       const __global Ti *iData, KParam iInfo,
                       uint groups_x, uint groups_y,
                       uint lim)
{

    const uint lidx = get_local_id(0);
    const uint lidy = get_local_id(1);
    const uint lid  = lidy * get_local_size(0) + lidx;

    const uint zid = get_group_id(0) / groups_x;
    const uint wid = get_group_id(1) / groups_y;
    const uint groupId_x = get_group_id(0) - (groups_x) * zid;
    const uint groupId_y = get_group_id(1) - (groups_y) * wid;
    const uint xid = groupId_x * get_local_size(0) * lim + lidx;
    const uint yid = groupId_y * get_local_size(1) + lidy;

    iData += wid * iInfo.strides[3] + zid * iInfo.strides[2] +
        yid * iInfo.strides[1] + iInfo.offset;

    tData += wid * tInfo.strides[3] + zid * tInfo.strides[2] +
        yid * tInfo.strides[1] + tInfo.offset;

    oData += wid * oInfo.strides[3] + zid * oInfo.strides[2] +
        yid * oInfo.strides[1] + oInfo.offset;

    bool cond_yzw = (yid < oInfo.dims[1]) && (zid < oInfo.dims[2]) && (wid < oInfo.dims[3]);

    __local To l_val[SHARED_MEM_SIZE];
    __local To l_tmp[DIMY];

    const uint l_off = (DIMY * (DIMX + 1));
    __local To *lData0 = l_val + lidy * (DIMX + 1);
    __local To *lData1 = l_val + lidy * (DIMX + 1) + l_off;

    const To init_val = init;
    uint id = xid;
    To val = init_val;

    const bool isLast = (lidx == (DIMX - 1));

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

        if (isLast) l_tmp[lidy] = val;

        bool cond = (cond_yzw && (id < oInfo.dims[0]));
        val = cond ? transform(iData[id]) : init_val;
        lData0[lidx] = val;
        barrier(CLK_LOCAL_MEM_FENCE);

        for (int off = 1; off < DIMX; off *= 2) {
            if (lidx >= off) val = binOp(val, lData0[(int)lidx - off]);
            lData1[lidx] = val;

            // Swap the pointers to lData0, lData1
            __local To *lData2 = lData0;
            lData0 = lData1;
            lData1 = lData2;

            barrier(CLK_LOCAL_MEM_FENCE);
        }

        val = binOp(val, l_tmp[lidy]);
        if (cond) oData[id] = val;
        id += DIMX;
    }

    if (!isFinalPass && isLast) {
        tData[groupId_x] = val;
    }
}

__kernel
void bcast_first_kernel(__global To *oData, KParam oInfo,
                        const __global To *tData, KParam tInfo,
                        uint groups_x, uint groups_y, uint lim)
{
    const uint lidx = get_local_id(0);
    const uint lidy = get_local_id(1);
    const uint lid  = lidy * get_local_size(0) + lidx;

    const uint zid = get_group_id(0) / groups_x;
    const uint wid = get_group_id(1) / groups_y;
    const uint groupId_x = get_group_id(0) - (groups_x) * zid;
    const uint groupId_y = get_group_id(1) - (groups_y) * wid;
    const uint xid = groupId_x * get_local_size(0) * lim + lidx;
    const uint yid = groupId_y * get_local_size(1) + lidy;

    tData += wid * tInfo.strides[3] + zid * tInfo.strides[2] +
        yid * tInfo.strides[1] + tInfo.offset;

    oData += wid * oInfo.strides[3] + zid * oInfo.strides[2] +
        yid * oInfo.strides[1] + oInfo.offset;

    bool cond = (yid < oInfo.dims[1]) && (zid < oInfo.dims[2]) && (wid < oInfo.dims[3]);

    if (!cond) return;
    if (groupId_x == 0) return;

    To accum = tData[groupId_x - 1];

    for (int k = 0, id = xid;
         k < lim && id < oInfo.dims[0];
         k++, id += DIMX) {

        oData[id] = binOp(accum, oData[id]);
    }

}

#if Ti == double
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
#endif

__kernel
void scan_first_kernel(__global To *oData, KParam oInfo,
                       __global To *tData, KParam tInfo,
                       const __global Ti *iData, KParam iInfo,
                       uint groups_x, uint groups_y,
                       uint lim)
{

    const uint lidx = get_local_id(0);
    const uint lidy = get_local_id(1);
    const uint lid  = lidy * get_local_size(0) + lidx;

    const uint zid = get_group_id(0) / groups_x;
    const uint wid = get_group_id(1) / groups_y;
    const uint groupId_x = get_group_id(0) - (groups_x) * zid;
    const uint groupId_y = get_group_id(1) - (groups_y) * wid;
    const uint xid = groupId_x * get_local_size(0) * lim + lidx;
    const uint yid = groupId_y * get_local_size(1) + lidy;

    iData += wid * iInfo.strides[3] + zid * iInfo.strides[2] +
        yid * iInfo.strides[1] + iInfo.offset;

    tData += wid * tInfo.strides[3] + zid * tInfo.strides[2] +
        yid * tInfo.strides[1] + tInfo.offset;

    oData += wid * oInfo.strides[3] + zid * oInfo.strides[2] +
        yid * oInfo.strides[1] + oInfo.offset;

    bool cond_yzw = (yid < oInfo.dims[1]) && (zid < oInfo.dims[2]) && (wid < oInfo.dims[3]);

    __local To l_val[SHARED_MEM_SIZE];
    __local To l_tmp[DIMY];

    const uint l_off = (DIMY * (DIMX + 1));
    __local To *lData0 = l_val + lidy * (DIMX + 1);
    __local To *lData1 = l_val + lidy * (DIMX + 1) + l_off;

    const To init_val = init;
    uint id = xid;
    To val = init_val;

    const bool isLast = (lidx == (DIMX - 1));

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

        if (isLast) l_tmp[lidy] = val;

        bool cond = (cond_yzw && (id < oInfo.dims[0]));
        val = cond ? transform(iData[id]) : init_val;
        lData0[lidx] = val;
        barrier(CLK_LOCAL_MEM_FENCE);

        for (int off = 1; off < DIMX; off *= 2) {
            if (lidx >= off) val = binOp(val, lData0[lidx - off]);
            lData1[lidx] = val;

            // Swap the pointers to lData0, lData1
            __local To *lData2 = lData0;
            lData0 = lData1;
            lData1 = lData2;

            barrier(CLK_LOCAL_MEM_FENCE);
        }

        val = binOp(val, l_tmp[lidy]);
        if (cond) oData[id] = val;
        id += DIMX;
    }

    if (!isFinalPass && isLast) {
        tData[groupId_x] = val;
    }
}

__kernel
void bcast_first_kernel(__global To *oData, KParam oInfo,
                        const __global To *tData, KParam tInfo,
                        uint groups_x, uint groups_y, uint lim)
{
    const uint lidx = get_local_id(0);
    const uint lidy = get_local_id(1);
    const uint lid  = lidy * get_local_size(0) + lidx;

    const uint zid = get_group_id(0) / groups_x;
    const uint wid = get_group_id(1) / groups_y;
    const uint groupId_x = get_group_id(0) - (groups_x) * zid;
    const uint groupId_y = get_group_id(1) - (groups_y) * wid;
    const uint xid = groupId_x * get_local_size(0) * lim + lidx;
    const uint yid = groupId_y * get_local_size(1) + lidy;

    tData += wid * tInfo.strides[3] + zid * tInfo.strides[2] +
        yid * tInfo.strides[1] + tInfo.offset;

    oData += wid * oInfo.strides[3] + zid * oInfo.strides[2] +
        yid * oInfo.strides[1] + oInfo.offset;

    bool cond = (yid < oInfo.dims[1]) && (zid < oInfo.dims[2]) && (wid < oInfo.dims[3]);

    if (!cond) return;
    if (groupId_x == 0) return;

    To accum = tData[groupId_x - 1];

    for (int k = 0, id = xid;
         k < lim && id < oInfo.dims[0];
         k++, id += DIMX) {

        oData[id] = binOp(accum, oData[id]);
    }

}


heatmap renderer interpolation fix

heatmap renderer interpolation fix

__constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST;

__kernel void renderToTexture(
        __global float* inputTensor,
        __write_only image2d_t output,
        __constant float* colors,
        __private float minConfidence,
        __private float maxOpacity,
        __private int channels
) {
    const int2 position = {get_global_id(0), get_global_id(1)};

    float4 color = {0.0f, 0.0f, 0.0f, 0.0f};
    for(int channel = 0; channel < channels; ++channel) {
        float intensity = inputTensor[(position.x + position.y*get_global_size(0))*channels + channel];
        intensity = clamp(intensity, 0.0f, 1.0f);

        if(intensity >= minConfidence) {
            float4 colorToUse = vload4(channel, colors);
            color += colorToUse*intensity;
        }
    }
    color = clamp(color, 0.0f, 1.0f);
    if(color.w == 0) { // none with intensity >= minConfidence or 0 found
        //color = (float4)(1.0f,1.0f,1.0f,0.0f);
        // Look for neighbors instead
        float highestConfidence = 0.0f;
        for(int a = -1; a <= 1; ++a) {
            for(int b = -1; b <= 1; ++b) {
                int2 nPos = {position.x + a, position.y + b};
                // Out of bounds check:
                if(nPos.x < 0 || nPos.y < 0 || nPos.x >= get_global_size(0) || nPos.y >= get_global_size(1))
                    continue;
                for(int channel = 0; channel < channels; ++channel) {
                    float intensity = inputTensor[(nPos.x + nPos.y*get_global_size(0))*channels + channel];

                    if(intensity >= minConfidence && intensity > highestConfidence) {
                        float4 colorToUse = vload4(channel, colors);
                        color = colorToUse;
                        color.w = 0.0f; // Set opacity to zero
                        highestConfidence = intensity;
                    }
                }
            }
        }
    } else {
        color.w *= maxOpacity;
    }
    write_imagef(output, (int2)(position.x, get_image_height(output) - position.y - 1), color);
}

__constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST;

__kernel void renderToTexture(
        __global float* inputTensor,
        __write_only image2d_t output,
        __constant float* colors,
        __private float minConfidence,
        __private float maxOpacity,
        __private int channels
) {
    const int2 position = {get_global_id(0), get_global_id(1)};

    float4 color = {0.0f, 0.0f, 0.0f, 0.0f};
    for(int channel = 0; channel < channels; ++channel) {
        float intensity = inputTensor[(position.x + position.y*get_global_size(0))*channels + channel];
        intensity = clamp(intensity, 0.0f, 1.0f);

        if(intensity >= minConfidence) {
            float4 colorToUse = vload4(channel, colors);
            color += colorToUse*intensity;
        }
    }
    color = clamp(color, 0.0f, 1.0f);
    if(color.w == 0) { // none with intensity >= minConfidence or 0 found
        color = (float4)(1.0f,1.0f,1.0f,0.0f);
    } else {
        color.w *= maxOpacity;
    }
    write_imagef(output, (int2)(position.x, get_image_height(output) - position.y - 1), color);
}