#ifndef GPU_RAZE
#define GPU_RAZE
#include "d_zero_elimination.h"
#include "d_repetition_elimination.h"
template <typename T>
static __device__ inline bool d_RAZE(int& csize, byte in [CS], byte out [CS], byte temp [CS])
{
const int tid = threadIdx.x;
const int size = csize / sizeof(T); const int extra = csize % sizeof(T);
const int bits = 8 * sizeof(T);
assert(CS == 16384);
T* const in_t = (T*)in; T* const out_t = (T*)out;
int* const count = (int*)temp; if (tid < bits) count[tid] = 0;
__syncthreads();
bool allzeros = true;
for (int i = tid; i < size; i += TPB) {
const T val = in_t[i];
if (val != 0) allzeros = false;
if constexpr (sizeof(T) == 8) {
const int keep = (val == 0) ? 0 : (64 - __builtin_clzll((long long)val));
atomicAdd_block(&count[keep], 1);
} else {
const int keep = (val == 0) ? 0 : (32 - __builtin_clz((int)val));
atomicAdd_block(&count[keep], 1);
}
}
allzeros = __syncthreads_and(allzeros);
if (allzeros) {
if constexpr (sizeof(T) > 1) {
if (tid < extra) out[tid] = in[csize - extra + tid];
}
if (tid == WS) {
out[extra] = bits + 1; out[extra + 1] = csize; out[extra + 2] = csize >> 8; }
csize = extra + 3;
return true;
}
if constexpr (bits <= WS) {
if (tid < WS) { const int lane = tid;
int pfs = count[lane];
int tmp = __shfl_up(pfs, 1);
if (lane >= 1) pfs += tmp;
tmp = __shfl_up(pfs, 2);
if (lane >= 2) pfs += tmp;
tmp = __shfl_up(pfs, 4);
if (lane >= 4) pfs += tmp;
if constexpr (bits > 8) {
tmp = __shfl_up(pfs, 8);
if (lane >= 8) pfs += tmp;
if constexpr (bits > 16) {
tmp = __shfl_up(pfs, 16);
if (lane >= 16) pfs += tmp;
#if defined(WS) && (WS == 64)
if constexpr (bits > 32) {
tmp = __shfl_up(pfs, 32);
if (lane >= 32) pfs += tmp;
}
#endif
}
}
count[lane] = pfs;
const int sav = (bits <= lane) ? -1 : ((bits - lane) * pfs);
int val = sav;
val = max(val, __shfl_xor(val, 1));
val = max(val, __shfl_xor(val, 2));
val = max(val, __shfl_xor(val, 4));
val = max(val, __shfl_xor(val, 8));
val = max(val, __shfl_xor(val, 16));
#if defined(WS) && (WS == 64)
val = max(val, __shfl_xor(val, 32));
const long long bal = __ballot(val == sav);
const int who = __ffsll(bal) - 1;
#else
static_assert(WS == 32);
const int bal = __ballot(val == sav);
const int who = __ffs(bal) - 1;
#endif
if (lane == 0) count[64] = val; if (lane == 0) count[65] = who; }
} else {
assert(bits == WS * 2);
if (tid < WS) { const int l0 = tid * 2;
const int l1 = l0 + 1;
const int lane = tid;
const int c1 = count[l1];
int pfs = count[l0] + c1;
int tmp = __shfl_up(pfs, 1);
if (lane >= 1) pfs += tmp;
tmp = __shfl_up(pfs, 2);
if (lane >= 2) pfs += tmp;
tmp = __shfl_up(pfs, 4);
if (lane >= 4) pfs += tmp;
if constexpr (bits > 8) {
tmp = __shfl_up(pfs, 8);
if (lane >= 8) pfs += tmp;
if constexpr (bits > 16) {
tmp = __shfl_up(pfs, 16);
if (lane >= 16) pfs += tmp;
#if defined(WS) && (WS == 64)
if constexpr (bits > 32) {
tmp = __shfl_up(pfs, 32);
if (lane >= 32) pfs += tmp;
}
#endif
}
}
count[l1] = pfs;
count[l0] = pfs - c1;
const int sav1 = (bits - l1) * pfs;
const int sav0 = (bits - l0) * (pfs - c1);
int val = max(sav0, sav1);
val = max(val, __shfl_xor(val, 1));
val = max(val, __shfl_xor(val, 2));
val = max(val, __shfl_xor(val, 4));
val = max(val, __shfl_xor(val, 8));
val = max(val, __shfl_xor(val, 16));
#if defined(WS) && (WS == 64)
val = max(val, __shfl_xor(val, 32));
const long long bal = __ballot((val == sav0) || (val == sav1));
const int who = __ffsll(bal) - 1;
#else
static_assert(WS == 32);
const int bal = __ballot((val == sav0) || (val == sav1));
const int who = __ffs(bal) - 1;
#endif
if (lane == who) {
count[64] = val; count[65] = (val == sav0) ? l0 : l1; }
}
}
__syncthreads();
const int saved = count[64];
const int keep = count[65];
const int countk = count[keep];
if (saved == 0) {
if (csize + 3 >= CS) return false;
for (int i = tid; i < size; i += TPB) {
out_t[i] = in_t[i];
}
if constexpr (sizeof(T) > 1) {
if (tid < extra) out[csize - extra + tid] = in[csize - extra + tid];
}
if (tid == 0) {
out[csize] = bits; out[csize + 1] = csize; out[csize + 2] = csize >> 8; }
csize += 3;
return true;
}
for (int i = tid + size - countk; i < size - countk + ((countk * keep + bits - 1) / bits); i += TPB) {
out_t[i] = 0;
}
__syncthreads();
byte* const bitmap = (byte*)&count[66];
const T tmask = ~(T)0 << keep; const T bmask = ~tmask;
const int ept = (((size + TPB - 1) / TPB + 7) / 8) * 8; int cnt = 0;
for (int i = tid * ept; i < min((tid + 1) * ept, size); i++) {
const T val = in_t[i];
if (0 != (val & tmask)) {
cnt++;
}
}
int wpos1 = block_prefix_sum(cnt, temp) - cnt;
int wloc2 = bits * (size - countk) + (tid * ept - wpos1) * keep;
int wpos2 = wloc2 / bits;
T oval = 0;
byte bmp = 0;
for (int i = tid * ept; i < min((tid + 1) * ept, size); i++) {
const T val = in_t[i];
if (0 != (val & tmask)) {
bmp |= 1 << (i % 8);
out_t[wpos1++] = val; } else {
if (keep != 0) {
const T bval = val & bmask;
const int shift = wloc2 % bits;
const int bms = bits - shift;
oval |= bval << shift;
if (bms <= keep) {
out_t[wpos2++] = oval; oval = bval >> bms;
}
wloc2 += keep;
}
}
if ((i % 8) == 7) {
bitmap[i / 8] = bmp;
bmp = 0;
}
}
if ((tid * ept < size) && ((tid + 1) * ept > size)) {
bitmap[size / 8] = bmp;
}
for (int i = tid + (size + 7) / 8; i < CS / bits; i += TPB) {
bitmap[i] = 0;
}
__syncthreads();
if ((wloc2 % bits) != 0) {
if constexpr (bits == 8) {
atomicOr_block((int*)&out_t[wpos2 & ~3], (int)oval << (8 * (wpos2 & 3)));
} else if constexpr (bits == 16) {
atomicOr_block((int*)&out_t[wpos2 & ~1], (int)oval << (16 * (wpos2 & 1)));
} else if constexpr (bits == 32) {
atomicOr_block((int*)&out_t[wpos2], (int)oval);
} else {
atomicOr_block((unsigned long long*)&out_t[wpos2], (unsigned long long)oval);
}
}
const int avail = CS - 3 - extra;
int wpos = (bits * (size - countk) + keep * countk + 7) / 8;
int base = 0 / sizeof(T);
int range = 2048 / sizeof(T);
cnt = avail - wpos;
if (!d_REencode<byte, 2048 / sizeof(T), true>(&bitmap[base], range, &out[wpos], cnt, &bitmap[base + range], (int*)temp)) return false;
wpos += cnt;
__syncthreads();
base = 2048 / sizeof(T);
range = 256 / sizeof(T);
cnt = avail - wpos;
if (!d_REencode<byte, 256 / sizeof(T), true>(&bitmap[base], range, &out[wpos], cnt, &bitmap[base + range], (int*)temp)) return false;
wpos += cnt;
__syncthreads();
base = (2048 + 256) / sizeof(T);
range = 32 / sizeof(T);
if constexpr (sizeof(T) < 8) {
cnt = avail - wpos;
if (!d_REencode<byte, 32 / sizeof(T), true>(&bitmap[base], range, &out[wpos], cnt, &bitmap[base + range], (int*)temp)) return false;
wpos += cnt;
base = (2048 + 256 + 32) / sizeof(T);
range = 4 / sizeof(T);
}
if (wpos >= avail - range) return false;
if (tid < range) { out[wpos + tid] = bitmap[base + tid];
}
wpos += range;
if constexpr (sizeof(T) > 1) {
if (tid < extra) out[wpos + tid] = in[csize - extra + tid];
}
const int new_size = wpos + 3 + extra;
if (tid == 0) {
out[new_size - 3] = keep; out[new_size - 2] = csize; out[new_size - 1] = csize >> 8; }
csize = new_size;
return true;
}
template <typename T>
static __device__ inline void d_iRAZE(int& csize, byte in [CS], byte out [CS], byte temp [CS])
{
const int oldsize = in[csize - 2] + ((int)in[csize - 1] << 8);
const int keep = in[csize - 3];
const int tid = threadIdx.x;
const int bits = 8 * sizeof(T); const int size = oldsize / sizeof(T); const int extra = oldsize % sizeof(T); T* const in_t = (T*)in; T* const out_t = (T*)out;
assert(TPB >= 256);
if (keep == bits + 1) { for (int i = tid; i < size; i += TPB) {
out_t[i] = 0;
}
} else if (keep == bits) { for (int i = tid; i < size; i += TPB) {
out_t[i] = in_t[i];
}
} else { assert(CS == 16384);
int rpos = csize - 3 - extra;
int* const temp_w = (int*)temp;
byte* const bitmap = (byte*)&temp_w[WS];
int base, range;
if constexpr (sizeof(T) == 8) {
base = (2048 + 256) / sizeof(T);
range = 32 / sizeof(T);
rpos -= range;
if (tid < range) bitmap[base + tid] = in[rpos + tid];
} else {
base = (2048 + 256 + 32) / sizeof(T);
range = 4 / sizeof(T);
rpos -= range;
if (tid < range) bitmap[base + tid] = in[rpos + tid];
rpos -= __syncthreads_count((tid < range * 8) && ((in[rpos + tid / 8] >> (tid % 8)) & 1));
base = (2048 + 256) / sizeof(T);
range = 32 / sizeof(T);
d_REdecode<byte, 32 / sizeof(T)>(range, &in[rpos], &bitmap[base + range], &bitmap[base], temp_w);
}
__syncthreads();
rpos -= __syncthreads_count((tid < range * 8) && ((bitmap[base + tid / 8] >> (tid % 8)) & 1));
base = 2048 / sizeof(T);
range = 256 / sizeof(T);
d_REdecode<byte, 256 / sizeof(T)>(range, &in[rpos], &bitmap[base + range], &bitmap[base], temp_w);
__syncthreads();
if constexpr (sizeof(T) >= 4) {
rpos -= __syncthreads_count((tid < range * 8) && ((bitmap[base + tid / 8] >> (tid % 8)) & 1));
}
if constexpr (sizeof(T) == 2) {
int sum = __syncthreads_count((tid < range * 8) && ((bitmap[base + tid / 8] >> (tid % 8)) & 1));
sum += __syncthreads_count((tid + TPB < range * 8) && ((bitmap[base + (tid + TPB) / 8] >> (tid % 8)) & 1));
rpos -= sum;
}
if constexpr (sizeof(T) == 1) {
int sum = 0;
for (int i = 0; i < TPB * 4; i += TPB) {
sum += __syncthreads_count((tid + i < range * 8) && ((bitmap[base + (tid + i) / 8] >> (tid % 8)) & 1));
}
rpos -= sum;
}
base = 0 / sizeof(T);
range = 2048 / sizeof(T);
d_REdecode<byte, 2048 / sizeof(T)>(range, &in[rpos], &bitmap[base + range], &bitmap[base], temp_w);
__syncthreads();
const int ept = (((size + TPB - 1) / TPB + 7) / 8) * 8; int cnt = 0;
for (int i = tid * ept; i < min((tid + 1) * ept, size); i += 8) {
cnt += __builtin_popcount((int)bitmap[i / 8]);
}
int rpos1 = block_prefix_sum(cnt, temp_w) - cnt;
const int count = temp_w[TPB / WS - 1];
int rloc2 = bits * count + (tid * ept - rpos1) * keep;
int rpos2 = rloc2 / bits;
const T tmask = ~(T)0 << keep; const T bmask = ~tmask; T ival = in_t[rpos2++];
byte bmp;
for (int i = tid * ept; i < min((tid + 1) * ept, size); i++) {
T val = 0;
if ((i % 8) == 0) bmp = bitmap[i / 8];
if ((bmp >> (i % 8)) & 1) {
val = in_t[rpos1++]; } else {
if (keep != 0) {
const int shift = rloc2 % bits;
const int bms = bits - shift;
T res = ival >> shift;
if (bms <= keep) {
ival = in_t[rpos2++];
res |= ival << bms;
}
rloc2 += keep;
val = res & bmask;
}
}
out_t[i] = val;
}
}
if constexpr (sizeof(T) > 1) {
if (tid < extra) {
out[oldsize - extra + tid] = in[csize - 3 - extra + tid];
}
}
csize = oldsize;
}
#endif