#ifndef repetition_elimination_device
#define repetition_elimination_device
template <typename T, bool check = false>
static __device__ inline bool d_REencodebyteshort(const T* const in, const int insize, T* const dataout, int& datasize, T* const bmout, int* const temp_w) {
using type = T;
using ull = unsigned long long;
const int bitsperword = 8 * sizeof(type);
const int bitsperlong = 8 * sizeof(ull);
const int wordsperlong = bitsperlong / bitsperword;
const int bytesperthread = CS / TPB;
const ull* const in_l = (ull*)in;
const int csize = insize * sizeof(T);
assert(bytesperthread % sizeof(ull) == 0);
assert(bytesperthread / sizeof(type) <= sizeof(int) * 8);
assert(bytesperthread / sizeof(ull) * wordsperlong >= 8);
assert(std::is_unsigned<type>::value);
const int tid = threadIdx.x;
int bmp = 0, cnt = 0;
if (tid * bytesperthread < csize) {
type prev = (tid == 0) ? 0 : in[tid * (bytesperthread / sizeof(type)) - 1];
for (int i = 0; i < bytesperthread / sizeof(ull); i++) {
const ull lval = in_l[tid * (bytesperthread / sizeof(ull)) + i];
const ull pval = (bitsperword < bitsperlong) ? ((lval << bitsperword) | prev) : prev;
int bm = 0;
for (int j = 0; j < wordsperlong; j++) {
const type val = lval >> (j * bitsperword);
const type prv = pval >> (j * bitsperword);
bm |= (val != prv) << j;
}
prev = lval >> (bitsperlong - bitsperword);
bmp |= bm << (i * wordsperlong);
}
if (tid * bytesperthread - (csize - bytesperthread) > 0) {
bmp &= ~(-1 << ((csize % bytesperthread + sizeof(type) - 1) / sizeof(type)));
}
if constexpr (sizeof(type) == 1) {
bmout[tid * 4] = bmp;
bmout[tid * 4 + 1] = bmp >> 8;
bmout[tid * 4 + 2] = bmp >> 16;
bmout[tid * 4 + 3] = bmp >> 24;
}
if constexpr (sizeof(type) == 2) bmout[tid] = bmp;
if constexpr (sizeof(type) == 4) ((byte*)bmout)[tid] = bmp;
cnt = __popc(bmp);
}
int pos = block_prefix_sum(cnt, temp_w);
if (tid == TPB - 1) temp_w[WS] = pos;
if constexpr (check) {
if (__syncthreads_or(pos > datasize)) return false;
} else {
__syncthreads();
}
pos -= cnt;
if (bmp != 0) {
for (int i = 0; i < bytesperthread / sizeof(ull); i++) {
const ull lval = in_l[tid * (bytesperthread / sizeof(ull)) + i];
const int bm = bmp >> (i * wordsperlong);
for (int j = 0; j < wordsperlong; j++) {
if ((bm >> j) & 1) {
dataout[pos++] = lval >> (j * bitsperword);
}
}
}
}
datasize = temp_w[WS];
return true;
}
template <typename T, bool check = false>
static __device__ inline bool d_REencode1wordperthread(const T* const in, const int insize, T* const dataout, int& datasize, T* const bmout, int* const temp_w) {
byte* const bmout_b = (byte*)bmout;
const int tid = threadIdx.x;
const int warp = tid / WS;
const int lane = tid % WS;
const bool active = (tid < insize);
const T prev = !active ? 0 : ((tid == 0) ? 0 : in[tid - 1]);
const T val = active ? in[tid] : 0;
const bool havenonrepval = (active && (val != prev));
#if defined(WS) && (WS == 64)
const unsigned long long tmp = __ballot(havenonrepval);
const int bm = (lane < 32) ? (int)tmp : (int)(tmp >> 32);
#else
const int bm = __ballot(havenonrepval);
#endif
const int cnt = __popc(bm);
const int subwarps = TPB / 32;
#if defined(WS) && (WS == 64)
const int sublane = lane & 31;
const int subwarp = threadIdx.x / 32;
if (active && (sublane % 8 == 0)) bmout_b[tid / 8] = bm >> sublane;
#else
const int sublane = lane;
const int subwarp = warp;
if (active && (lane % 8 == 0)) bmout_b[tid / 8] = bm >> lane;
#endif
if constexpr (sizeof(T) > 1) { if (warp == 0) {
const int base = (insize + 7) / 8;
const int top = (insize + (sizeof(T) * 8 - 1)) / 8;
if (base + tid < top) bmout_b[base + tid] = 0;
}
}
if (sublane == 0) temp_w[subwarp] = cnt;
__syncthreads();
int sum = 0;
if (warp == 0) {
if (lane < subwarps) sum = temp_w[lane];
for (int i = 1; i < subwarps; i *= 2) {
const int tmp = __shfl_up(sum, i);
if (lane >= i) sum += tmp;
}
temp_w[lane] = sum;
}
if constexpr (check) {
if (__syncthreads_or(sum > datasize)) return false;
} else {
__syncthreads();
}
if (havenonrepval) {
const int loc = temp_w[subwarp] - cnt + __popc(bm & ((1 << sublane) - 1));
dataout[loc] = val;
}
datasize = temp_w[subwarps - 1];
return true;
}
template <typename T, bool check = false>
static __device__ inline bool d_REencode2wordsperthread(const T* const in, const int insize, T* const dataout, int& datasize, T* const bmout, int* const temp_w) {
byte* const bmout_b = (byte*)bmout;
const int tid = threadIdx.x;
const int warp = tid / WS;
const int lane = tid % WS;
const int tid1 = tid * 2;
const int tid2 = tid1 + 1;
const bool active1 = (tid1 < insize);
const bool active2 = (tid2 < insize);
const T prev = (!active1) ? 0 : ((tid1 == 0) ? 0 : in[tid1 - 1]);
const T val1 = active1 ? in[tid1] : 0;
const T val2 = active2 ? in[tid2] : 0;
const bool havenonrepval1 = (active1 && (val1 != prev));
const bool havenonrepval2 = (active2 && (val2 != val1));
#if defined(WS) && (WS == 64)
const unsigned long long temp = __ballot(havenonrepval1);
const int bm1 = (lane < 32) ? (int)temp : (int)(temp >> 32);
const unsigned long long temp1 = __ballot(havenonrepval2);
const int bm2 = (lane < 32) ? (int)temp1 : (int)(temp1 >> 32);
#else
const int bm1 = __ballot(havenonrepval1);
const int bm2 = __ballot(havenonrepval2);
#endif
const int cnt = __popc(bm1) + __popc(bm2);
const int comb = havenonrepval1 + havenonrepval2 * 2;
#if defined(WS) && (WS == 64)
const int sublane = lane & 31;
const int tmp1 = __shfl(comb, sublane / 2, 32) >> (lane % 2);
const unsigned long long temp2 = __ballot(tmp1 & 1);
const int bmlo = (lane < 32) ? (int)temp2 : (int)(temp2 >> 32);
#else
const int sublane = lane;
const int tmp1 = __shfl(comb, lane / 2) >> (lane % 2);
const int bmlo = __ballot(tmp1 & 1);
#endif
#if defined(WS) && (WS == 64)
const int tmp2 = __shfl(comb, 16 + sublane / 2, 32) >> (lane % 2);
const unsigned long long temp3 = __ballot(tmp2 & 1);
const int bmhi = (lane < 32) ? (int)temp3 : (int)(temp3 >> 32);
#else
const int tmp2 = __shfl(comb, 16 + lane / 2) >> (lane % 2);
const int bmhi = __ballot(tmp2 & 1);
#endif
const int subwarps = TPB / 32;
#if defined(WS) && (WS == 64)
const int subwarp = threadIdx.x / 32;
if ((((__ballot(active1) >> (lane & 32)) & 0xffff'ffff) != 0) && (sublane % 8 == 0)) bmout_b[subwarp * 8 + sublane / 8] = bmlo >> sublane;
if ((((__ballot(active2) >> (lane & 32)) & 0xffff'ffff) != 0) && (sublane % 8 == 0)) bmout_b[subwarp * 8 + sublane / 8 + 4] = bmhi >> sublane;
#else
const int subwarp = warp;
if (__any(active1) && (lane % 8 == 0)) bmout_b[warp * 8 + lane / 8] = bmlo >> lane;
if (__any(active2) && (lane % 8 == 0)) bmout_b[warp * 8 + lane / 8 + 4] = bmhi >> lane;
#endif
if constexpr (sizeof(T) > 1) { if (warp == 0) {
const int base = (insize + 7) / 8;
const int top = (insize + (sizeof(T) * 8 - 1)) / 8;
if (base + tid < top) bmout_b[base + tid] = 0;
}
}
if (sublane == 0) temp_w[subwarp] = cnt;
__syncthreads();
int sum = 0;
if (warp == 0) {
if (lane < subwarps) sum = temp_w[lane];
for (int i = 1; i < subwarps; i *= 2) {
const int tmp = __shfl_up(sum, i);
if (lane >= i) sum += tmp;
}
temp_w[lane] = sum;
}
if constexpr (check) {
if (__syncthreads_or(sum > datasize)) return false;
} else {
__syncthreads();
}
int loc = temp_w[subwarp] - cnt + __popc(bm1 & ((1 << sublane) - 1)) + __popc(bm2 & ((1 << sublane) - 1));
if (havenonrepval1) dataout[loc++] = val1;
if (havenonrepval2) dataout[loc] = val2;
datasize = temp_w[subwarps - 1];
return true;
}
template <typename T, bool check = false>
static __device__ inline bool d_REencode4wordsperthread(const T* const in, const int insize, T* const dataout, int& datasize, T* const bmout, int* const temp_w) {
byte* const bmout_b = (byte*)bmout;
const int tid = threadIdx.x;
const int warp = tid / WS;
const int lane = tid % WS;
const int tid1 = tid * 4;
const int tid2 = tid1 + 1;
const int tid3 = tid2 + 1;
const int tid4 = tid3 + 1;
const bool active1 = (tid1 < insize);
const bool active2 = (tid2 < insize);
const bool active3 = (tid3 < insize);
const bool active4 = (tid4 < insize);
const T prev = !active1 ? 0 : ((tid1 == 0) ? 0 : in[tid1 - 1]);
const T val1 = active1 ? in[tid1] : 0;
const T val2 = active2 ? in[tid2] : 0;
const T val3 = active3 ? in[tid3] : 0;
const T val4 = active4 ? in[tid4] : 0;
const bool havenonrepval1 = (active1 && (val1 != prev));
const bool havenonrepval2 = (active2 && (val2 != val1));
const bool havenonrepval3 = (active3 && (val3 != val2));
const bool havenonrepval4 = (active4 && (val4 != val3));
#if defined(WS) && (WS == 64)
const unsigned long long temp1 = __ballot(havenonrepval1);
const int bm1 = (lane < 32) ? (int)temp1 : (int)(temp1 >> 32);
const unsigned long long temp2 = __ballot(havenonrepval2);
const int bm2 = (lane < 32) ? (int)temp2 : (int)(temp2 >> 32);
const unsigned long long temp3 = __ballot(havenonrepval3);
const int bm3 = (lane < 32) ? (int)temp3 : (int)(temp3 >> 32);
const unsigned long long temp4 = __ballot(havenonrepval4);
const int bm4 = (lane < 32) ? (int)temp4 : (int)(temp4 >> 32);
#else
const int bm1 = __ballot(havenonrepval1);
const int bm2 = __ballot(havenonrepval2);
const int bm3 = __ballot(havenonrepval3);
const int bm4 = __ballot(havenonrepval4);
#endif
const int cnt = __popc(bm1) + __popc(bm2) + __popc(bm3) + __popc(bm4);
const int comb = havenonrepval1 + havenonrepval2 * 2 + havenonrepval3 * 4 + havenonrepval4 * 8;
#if defined(WS) && (WS == 64)
const int sublane = lane & 31;
const int tmp1 = __shfl(comb, sublane / 4, 32) >> (lane % 4);
const unsigned long long temp5 = __ballot(tmp1 & 1);
const int bmA = (lane < 32) ? (int)temp5 : (int)(temp5 >> 32);
#else
const int sublane = lane;
const int tmp1 = __shfl(comb, lane / 4) >> (lane % 4);
const int bmA = __ballot(tmp1 & 1);
#endif
#if defined(WS) && (WS == 64)
const int tmp2 = __shfl(comb, 8 + sublane / 4, 32) >> (lane % 4);
const unsigned long long temp6 = __ballot(tmp2 & 1);
const int bmB = (lane < 32) ? (int)temp6 : (int)(temp6 >> 32);
#else
const int tmp2 = __shfl(comb, 8 + lane / 4) >> (lane % 4);
const int bmB = __ballot(tmp2 & 1);
#endif
#if defined(WS) && (WS == 64)
const int tmp3 = __shfl(comb, 16 + sublane / 4, 32) >> (lane % 4);
const unsigned long long temp7 = __ballot(tmp3 & 1);
const int bmC = (lane < 32) ? (int)temp7 : (int)(temp7 >> 32);
#else
const int tmp3 = __shfl(comb, 16 + lane / 4) >> (lane % 4);
const int bmC = __ballot(tmp3 & 1);
#endif
#if defined(WS) && (WS == 64)
const int tmp4 = __shfl(comb, 24 + sublane / 4, 32) >> (lane % 4);
const unsigned long long temp8 = __ballot(tmp4 & 1);
const int bmD = (lane < 32) ? (int)temp8 : (int)(temp8 >> 32);
#else
const int tmp4 = __shfl(comb, 24 + lane / 4) >> (lane % 4);
const int bmD = __ballot(tmp4 & 1);
#endif
const int subwarps = TPB / 32;
#if defined(WS) && (WS == 64)
const int subwarp = threadIdx.x / 32;
if ((((__ballot(active1) >> (lane & 32)) & 0xffff'ffff) != 0) && (sublane % 8 == 0)) bmout_b[subwarp * 16 + sublane / 8] = bmA >> sublane;
if ((((__ballot(active2) >> (lane & 32)) & 0xffff'ffff) != 0) && (sublane % 8 == 0)) bmout_b[subwarp * 16 + sublane / 8 + 4] = bmB >> sublane;
if ((((__ballot(active3) >> (lane & 32)) & 0xffff'ffff) != 0) && (sublane % 8 == 0)) bmout_b[subwarp * 16 + sublane / 8 + 8] = bmC >> sublane;
if ((((__ballot(active4) >> (lane & 32)) & 0xffff'ffff) != 0) && (sublane % 8 == 0)) bmout_b[subwarp * 16 + sublane / 8 + 12] = bmD >> sublane;
#else
const int subwarp = warp;
if (__any(active1) && (lane % 8 == 0)) bmout_b[warp * 16 + lane / 8] = bmA >> lane;
if (__any(active2) && (lane % 8 == 0)) bmout_b[warp * 16 + lane / 8 + 4] = bmB >> lane;
if (__any(active3) && (lane % 8 == 0)) bmout_b[warp * 16 + lane / 8 + 8] = bmC >> lane;
if (__any(active4) && (lane % 8 == 0)) bmout_b[warp * 16 + lane / 8 + 12] = bmD >> lane;
#endif
if constexpr (sizeof(T) > 1) { if (warp == 0) {
const int base = (insize + 7) / 8;
const int top = (insize + (sizeof(T) * 8 - 1)) / 8;
if (base + tid < top) bmout_b[base + tid] = 0;
}
}
if (sublane == 0) temp_w[subwarp] = cnt;
__syncthreads();
int sum = 0;
if (warp == 0) {
if (lane < subwarps) sum = temp_w[lane];
for (int i = 1; i < subwarps; i *= 2) {
const int tmp = __shfl_up(sum, i);
if (lane >= i) sum += tmp;
}
temp_w[lane] = sum;
}
if constexpr (check) {
if (__syncthreads_or(sum > datasize)) return false;
} else {
__syncthreads();
}
int loc = temp_w[subwarp] - cnt + __popc(bm1 & ((1 << sublane) - 1)) + __popc(bm2 & ((1 << sublane) - 1)) + __popc(bm3 & ((1 << sublane) - 1)) + __popc(bm4 & ((1 << sublane) - 1));
if (havenonrepval1) dataout[loc++] = val1;
if (havenonrepval2) dataout[loc++] = val2;
if (havenonrepval3) dataout[loc++] = val3;
if (havenonrepval4) dataout[loc] = val4;
datasize = temp_w[subwarps - 1];
return true;
}
template <int X, typename T, bool check = false>
static __device__ inline bool d_REencodeXwordsperthread(const T* const in, const int insize, T* const dataout, int& datasize, T* const bmout, int* const temp_w) {
assert((X == 8) || (X == 16) || (X == 32));
const int WPT = X; const int tid = threadIdx.x;
int bmp = 0, cnt = 0;
if (tid * WPT < insize) {
T prev = (tid == 0) ? 0 : in[tid * WPT - 1];
for (int i = 0; i < WPT; i++) {
const T val = in[tid * WPT + i];
bmp |= (val != prev) << i;
prev = val;
}
if (tid * WPT - (insize - WPT) > 0) {
bmp &= ~(-1 << (insize % WPT));
}
if constexpr (X == 8) ((byte*)bmout)[tid] = bmp;
if constexpr (X == 16) ((short*)bmout)[tid] = bmp;
if constexpr (X == 32) ((int*)bmout)[tid] = bmp;
cnt = __popc(bmp);
}
if constexpr (sizeof(T) * 8 > X) { if (tid < WS) {
const int base = (insize + (X - 1)) / 8;
const int top = (insize + (sizeof(T) * 8 - 1)) / 8;
if (base + tid < top) ((byte*)bmout)[base + tid] = 0;
}
}
int pos = block_prefix_sum(cnt, temp_w);
if (tid == TPB - 1) temp_w[WS] = pos;
if constexpr (check) {
if (__syncthreads_or(pos > datasize)) return false;
} else {
__syncthreads();
}
pos -= cnt;
if (bmp != 0) {
for (int i = 0; i < WPT; i++) {
if ((bmp >> i) & 1) {
const T val = in[tid * WPT + i];
dataout[pos++] = val;
}
}
}
datasize = temp_w[WS];
return true;
}
template <typename T, int maxsize = CS, bool check = false> static __device__ inline bool d_REencode(const T* const in, const int insize, T* const dataout, int& datasize, T* const bmout, int* const temp_w) {
assert((TPB & (TPB - 1)) == 0);
assert((maxsize & (maxsize - 1)) == 0);
assert(maxsize % sizeof(T) == 0);
assert((maxsize / sizeof(T) % TPB == 0) || (maxsize / sizeof(T) < TPB));
const int wordsperthread = maxsize / sizeof(T) / TPB;
if constexpr ((sizeof(T) <= 2) && (maxsize > 2048)) {
return d_REencodebyteshort<T, check>(in, insize, dataout, datasize, bmout, temp_w);
} else if constexpr (wordsperthread <= 1) {
return d_REencode1wordperthread<T, check>(in, insize, dataout, datasize, bmout, temp_w);
} else if constexpr (wordsperthread == 2) {
return d_REencode2wordsperthread<T, check>(in, insize, dataout, datasize, bmout, temp_w);
} else if constexpr (wordsperthread == 4) {
return d_REencode4wordsperthread<T, check>(in, insize, dataout, datasize, bmout, temp_w);
} else if constexpr (wordsperthread == 8) {
return d_REencodeXwordsperthread<8, T, check>(in, insize, dataout, datasize, bmout, temp_w);
} else if constexpr (wordsperthread == 16) {
return d_REencodeXwordsperthread<16, T, check>(in, insize, dataout, datasize, bmout, temp_w);
} else if constexpr (wordsperthread == 32) {
return d_REencodeXwordsperthread<32, T, check>(in, insize, dataout, datasize, bmout, temp_w);
} else {
__trap();
return false;
}
}
template <typename T, typename U> static __device__ inline void d_REdecode_specialized(const int decsize, const T* const datain, const U* const bmin_t, T* const out, int* const temp_w) {
const int subWS = 32;
const int tid = threadIdx.x;
const int subwarp = tid / subWS;
const int subwarps = TPB / subWS;
const int sublane = tid % subWS;
int num = (decsize + subWS - 1) / subWS; if constexpr (sizeof(T) == 8) num += num & 1;
const int beg = subwarp * num / subwarps;
const int end = (subwarp + 1) * num / subwarps;
int cnt = 0;
for (int i = beg * (4 / sizeof(U)) + sublane; i < end * (4 / sizeof(U)); i += subWS) {
const int bm = bmin_t[i];
cnt += __popc(bm);
}
for (int i = 1; i < subWS; i *= 2) {
cnt += __shfl_xor(cnt, i, subWS);
}
if (sublane == 0) temp_w[subwarp] = cnt;
__syncthreads();
if (tid < WS) {
const int lane = tid % WS;
int sum = temp_w[lane];
for (int i = 1; i < subwarps; i *= 2) {
const int tmp = __shfl_up(sum, i);
if (lane >= i) sum += tmp;
}
temp_w[lane] = sum;
}
__syncthreads();
int pos = temp_w[subwarp] - cnt;
for (int i = beg; i < end; i++) {
int bm;
if constexpr (sizeof(U) == 1) {
bm = (int)bmin_t[i * 4 + sublane / 8] << (sublane & ~7);
bm |= __shfl_xor(bm, 8, subWS);
bm |= __shfl_xor(bm, 16, subWS);
}
if constexpr (sizeof(U) == 2) {
bm = (int)bmin_t[i * 2 + sublane / 16] << (sublane & ~15);
bm |= __shfl_xor(bm, 16, subWS);
}
if constexpr (sizeof(U) == 4) {
bm = bmin_t[i];
}
const int offs = __popc(bm & ((1 << sublane) - 1)) - (((bm >> sublane) & 1) ^ 1);
const T val = (pos + offs < 0) ? 0 : datain[pos + offs];
const int loc = i * subWS + sublane;
if (loc < decsize) out[loc] = val;
pos += __popc(bm);
}
}
template <typename T>
static __device__ inline void d_REdecode1wordperthread(const int decsize, const T* const datain, const T* const bmin, T* const out, int* const temp_w) {
const byte* const bmin_b = (byte*)bmin;
const int tid = threadIdx.x;
const int subWS = 32;
const int subwarps = TPB / subWS;
const int subwarp = tid / subWS;
const int sublane = tid % subWS;
const int warp = tid / WS;
const int lane = tid % WS;
const bool active = (tid < decsize);
const bool havenonrepval = (active && ((bmin_b[tid / 8] >> (tid % 8)) & 1));
#if defined(WS) && (WS == 64)
const unsigned long long tmp = __ballot(havenonrepval);
const int bm = (lane < 32) ? (int)tmp : (int)(tmp >> 32);
#else
const int bm = __ballot(havenonrepval);
#endif
const int cnt = __popc(bm);
if (sublane == 0) temp_w[subwarp] = cnt;
__syncthreads();
int sum = 0;
if (warp == 0) {
if (lane < subwarps) sum = temp_w[lane];
for (int i = 1; i < subwarps; i *= 2) {
const int tmp = __shfl_up(sum, i);
if (lane >= i) sum += tmp;
}
temp_w[lane] = sum;
}
__syncthreads();
if (active) {
const int loc = temp_w[subwarp] - cnt + __popc(bm & ((1 << sublane) - 1)) - (havenonrepval ^ 1);
out[tid] = (loc < 0) ? 0 : datain[loc];
}
}
template <typename T>
static __device__ inline void d_REdecode2wordsperthread(const int decsize, const T* const datain, const T* const bmin, T* const out, int* const temp_w) {
const byte* const bmin_b = (byte*)bmin;
const int tid = threadIdx.x;
const int subWS = 32;
const int subwarps = TPB / subWS;
const int subwarp = tid / subWS;
const int sublane = tid % subWS;
const int warp = tid / WS;
const int lane = tid % WS;
const int tid1 = tid * 2;
const int tid2 = tid1 + 1;
const bool active1 = (tid1 < decsize);
const bool active2 = (tid2 < decsize);
const byte b = active1 ? (bmin_b[tid1 / 8] >> (tid1 % 8)) : 0;
const bool havenonrepval1 = (active1 && (b & 1));
const bool havenonrepval2 = (active2 && (b & 2));
#if defined(WS) && (WS == 64)
const unsigned long long temp = __ballot(havenonrepval1);
const int bm1 = (lane < 32) ? (int)temp : (int)(temp >> 32);
const unsigned long long temp1 = __ballot(havenonrepval2);
const int bm2 = (lane < 32) ? (int)temp1 : (int)(temp1 >> 32);
#else
const int bm1 = __ballot(havenonrepval1);
const int bm2 = __ballot(havenonrepval2);
#endif
const int cnt = __popc(bm1) + __popc(bm2);
if (sublane == 0) temp_w[subwarp] = cnt;
__syncthreads();
int sum = 0;
if (warp == 0) {
if (lane < subwarps) sum = temp_w[lane];
for (int i = 1; i < subwarps; i *= 2) {
const int tmp = __shfl_up(sum, i);
if (lane >= i) sum += tmp;
}
temp_w[lane] = sum;
}
__syncthreads();
const int common = temp_w[subwarp] - cnt + __popc(bm1 & ((1 << sublane) - 1)) + __popc(bm2 & ((1 << sublane) - 1));
const int loc1 = common - (havenonrepval1 ^ 1);
const int loc2 = common + havenonrepval1 - (havenonrepval2 ^ 1);
if (active1) out[tid1] = (loc1 < 0) ? 0 : datain[loc1];
if (active2) out[tid2] = (loc2 < 0) ? 0 : datain[loc2];
}
template <typename T>
static __device__ inline void d_REdecode4wordsperthread(const int decsize, const T* const datain, const T* const bmin, T* const out, int* const temp_w) {
const byte* const bmin_b = (byte*)bmin;
const int tid = threadIdx.x;
const int subWS = 32;
const int subwarps = TPB / subWS;
const int subwarp = tid / subWS;
const int sublane = tid % subWS;
const int warp = tid / WS;
const int lane = tid % WS;
const int tid1 = tid * 4;
const int tid2 = tid1 + 1;
const int tid3 = tid2 + 1;
const int tid4 = tid3 + 1;
const bool active1 = (tid1 < decsize);
const bool active2 = (tid2 < decsize);
const bool active3 = (tid3 < decsize);
const bool active4 = (tid4 < decsize);
const byte b = active1 ? (bmin_b[tid1 / 8] >> (tid1 % 8)) : 0;
const bool havenonrepval1 = (active1 && (b & 1));
const bool havenonrepval2 = (active2 && (b & 2));
const bool havenonrepval3 = (active3 && (b & 4));
const bool havenonrepval4 = (active4 && (b & 8));
#if defined(WS) && (WS == 64)
const unsigned long long temp = __ballot(havenonrepval1);
const int bm1 = (lane < 32) ? (int)temp : (int)(temp >> 32);
const unsigned long long temp1 = __ballot(havenonrepval2);
const int bm2 = (lane < 32) ? (int)temp1 : (int)(temp1 >> 32);
const unsigned long long temp2 = __ballot(havenonrepval3);
const int bm3 = (lane < 32) ? (int)temp2 : (int)(temp2 >> 32);
const unsigned long long temp3 = __ballot(havenonrepval4);
const int bm4 = (lane < 32) ? (int)temp3 : (int)(temp3 >> 32);
#else
const int bm1 = __ballot(havenonrepval1);
const int bm2 = __ballot(havenonrepval2);
const int bm3 = __ballot(havenonrepval3);
const int bm4 = __ballot(havenonrepval4);
#endif
const int cnt = __popc(bm1) + __popc(bm2) + __popc(bm3) + __popc(bm4);
if (sublane == 0) temp_w[subwarp] = cnt;
__syncthreads();
int sum = 0;
if (warp == 0) {
if (lane < subwarps) sum = temp_w[lane];
for (int i = 1; i < subwarps; i *= 2) {
const int tmp = __shfl_up(sum, i);
if (lane >= i) sum += tmp;
}
temp_w[lane] = sum;
}
__syncthreads();
const int common = temp_w[subwarp] - cnt + __popc(bm1 & ((1 << sublane) - 1)) + __popc(bm2 & ((1 << sublane) - 1)) + __popc(bm3 & ((1 << sublane) - 1)) + __popc(bm4 & ((1 << sublane) - 1));
const int loc1 = common - (havenonrepval1 ^ 1);
const int loc2 = common + havenonrepval1 - (havenonrepval2 ^ 1);
const int loc3 = common + havenonrepval1 + havenonrepval2 - (havenonrepval3 ^ 1);
const int loc4 = common + havenonrepval1 + havenonrepval2 + havenonrepval3 - (havenonrepval4 ^ 1);
if (active1) out[tid1] = (loc1 < 0) ? 0 : datain[loc1];
if (active2) out[tid2] = (loc2 < 0) ? 0 : datain[loc2];
if (active3) out[tid3] = (loc3 < 0) ? 0 : datain[loc3];
if (active4) out[tid4] = (loc4 < 0) ? 0 : datain[loc4];
}
template <int X, typename T>
static __device__ inline void d_REdecodeXwordsperthread(const int decsize, const T* const datain, const T* const bmin, T* const out, int* const temp_w) {
assert((X == 8) || (X == 16) || (X == 32));
const int WPT = X; const int tid = threadIdx.x;
int bmp, cnt = 0;
if (tid * WPT < decsize) {
if constexpr (X == 8) bmp = ((byte*)bmin)[tid];
if constexpr (X == 16) bmp = ((unsigned short*)bmin)[tid];
if constexpr (X == 32) bmp = ((int*)bmin)[tid];
cnt = __popc(bmp);
}
int pos = block_prefix_sum(cnt, temp_w) - cnt;
if (tid * WPT < decsize) {
T val = (bmp & 1) ? 0 : ((pos > 0) ? datain[pos - 1] : 0);
if ((tid | 31) * WPT + (WPT - 1) < decsize) {
for (int i = 0; i < WPT; i++) {
if ((bmp >> i) & 1) val = datain[pos++];
out[tid * WPT + i] = val;
}
} else {
for (int i = 0; i < WPT; i++) {
if (tid * WPT + i >= decsize) break;
if ((bmp >> i) & 1) val = datain[pos++];
out[tid * WPT + i] = val;
}
}
}
}
template <typename T, int maxsize = CS> static __device__ inline void d_REdecode_small(const int decsize, const T* const datain, const T* const bmin, T* const out, int* const temp_w) {
assert((TPB & (TPB - 1)) == 0);
assert((maxsize & (maxsize - 1)) == 0);
assert(maxsize % sizeof(T) == 0);
assert((maxsize / sizeof(T) % TPB == 0) || (maxsize / sizeof(T) < TPB));
const int wordsperthread = maxsize / sizeof(T) / TPB;
if constexpr (wordsperthread <= 1) {
d_REdecode1wordperthread<T>(decsize, datain, bmin, out, temp_w);
} else if constexpr (wordsperthread == 2) {
d_REdecode2wordsperthread<T>(decsize, datain, bmin, out, temp_w);
} else if constexpr (wordsperthread == 4) {
d_REdecode4wordsperthread<T>(decsize, datain, bmin, out, temp_w);
} else if constexpr (wordsperthread == 8) {
d_REdecodeXwordsperthread<8, T>(decsize, datain, bmin, out, temp_w);
} else if constexpr (wordsperthread == 16) {
d_REdecodeXwordsperthread<16, T>(decsize, datain, bmin, out, temp_w);
} else if constexpr (wordsperthread == 32) {
d_REdecodeXwordsperthread<32, T>(decsize, datain, bmin, out, temp_w);
} else {
__trap();
}
}
template <typename T, int maxsize = CS>
static __device__ inline void d_REdecode(const int decsize, const T* const datain, const T* const bmin, T* const out, int* const temp_w) {
if constexpr (maxsize <= 2048) {
d_REdecode_small<T, maxsize>(decsize, datain, bmin, out, temp_w);
} else if ((sizeof(T) >= 4) ) { d_REdecode_specialized(decsize, datain, (int*)bmin, out, temp_w);
} else if constexpr (sizeof(T) == 2) { const int tid = threadIdx.x;
const int num = (decsize + 15) / 16;
const int beg = tid * num / TPB;
const int end = (tid + 1) * num / TPB;
int cnt = 0;
for (int i = beg; i < end; i++) {
const unsigned short bm = bmin[i];
cnt += __popc((int)bm);
}
int pos = block_prefix_sum(cnt, temp_w) - cnt;
short val = (pos > 0) ? datain[pos - 1] : 0;
for (int i = beg; i < end; i++) {
const unsigned short bm = bmin[i];
for (int j = 0; j < 16; j++) {
if ((bm >> j) & 1) val = datain[pos++];
if (i * 16 + j < decsize) out[i * 16 + j] = val;
}
}
} else { const int tid = threadIdx.x;
const int num = (decsize + 7) / 8; long long* const out_l = (long long*)out;
assert(num <= TPB * 4);
const int beg = tid * num / TPB;
const int end = (tid + 1) * num / TPB;
int bmp = 0;
for (int i = beg; i < end; i++) {
bmp |= (int)bmin[i] << (8 * (i - beg));
}
const int cnt = __popc(bmp);
int pos = block_prefix_sum(cnt, temp_w) - cnt;
long long val = (pos > 0) ? datain[pos - 1] : 0;
for (int i = beg; i < end; i++) {
const byte bm = bmp >> (8 * (i - beg));
long long lval = 0;
for (int j = 0; j < 8; j++) {
if ((bm >> j) & 1) val = datain[pos++];
lval |= val << (j * 8);
}
out_l[i] = lval;
}
}
}
#endif