#include #include #include #include template __global__ void packed_gemv(T* out, const uint8_t* x, const uint8_t* w, const float* xn, const c10::BFloat16* wn, const int8_t* ac, const int8_t* wc, const T* bias, int n, int packed_k, float as, float ws) { const int lane = threadIdx.x & 31; const int col = blockIdx.x * 4 + threadIdx.x / 32; const int row = blockIdx.y; __shared__ int a_codes[16], w_codes[16]; if (threadIdx.x < 16) { a_codes[threadIdx.x] = ac[threadIdx.x]; w_codes[threadIdx.x] = wc[threadIdx.x]; } __syncthreads(); if (col >= n) return; int sum = 0; if (packed_k % 4 == 0 && (reinterpret_cast(x) & 3) == 0 && (reinterpret_cast(w) & 3) == 0) { const uint32_t* xp = reinterpret_cast(x + row * packed_k); const uint32_t* wp = reinterpret_cast(w + col * packed_k); for (int k = lane; k < packed_k / 4; k += 32) { const uint32_t av = xp[k], bv = wp[k]; uint32_t al = 0, ah = 0, bl = 0, bh = 0; #pragma unroll for (int j = 0; j < 4; ++j) { al |= uint32_t(uint8_t(a_codes[(av >> (j * 8)) & 15])) << (j * 8); ah |= uint32_t(uint8_t(a_codes[(av >> (j * 8 + 4)) & 15])) << (j * 8); bl |= uint32_t(uint8_t(w_codes[(bv >> (j * 8)) & 15])) << (j * 8); bh |= uint32_t(uint8_t(w_codes[(bv >> (j * 8 + 4)) & 15])) << (j * 8); } sum = __dp4a(static_cast(al), static_cast(bl), sum); sum = __dp4a(static_cast(ah), static_cast(bh), sum); } } else { for (int k = lane; k < packed_k; k += 32) { const uint8_t a = x[row * packed_k + k]; const uint8_t b = w[col * packed_k + k]; sum += a_codes[a & 15] * w_codes[b & 15]; sum += a_codes[a >> 4] * w_codes[b >> 4]; } } #pragma unroll for (int offset = 16; offset; offset >>= 1) sum += __shfl_down_sync(0xffffffff, sum, offset); if (lane == 0) { float value = static_cast(sum); value *= xn[row] * static_cast(wn[col]) * (as * ws); if (bias) value += static_cast(bias[col]); out[row * n + col] = static_cast(value); } } void orbitquant_gemv(torch::Tensor &out, torch::Tensor const &x, torch::Tensor const &w, torch::Tensor const &xn, torch::Tensor const &wn, torch::Tensor const &ac, torch::Tensor const &wc, torch::Tensor const &bias, bool has_bias, double activation_scale, double weight_scale) { TORCH_CHECK(x.is_cuda() && x.scalar_type() == torch::kUInt8 && x.dim() == 2, "x must be rank-2 packed CUDA uint8"); const torch::Tensor* tensors[] = {&out, &w, &xn, &wn, &ac, &wc}; for (const auto* t : tensors) { TORCH_CHECK(t->device() == x.device() && t->is_contiguous(), "tensors must be contiguous on the input CUDA device"); } TORCH_CHECK(x.is_contiguous() && w.scalar_type() == torch::kUInt8, "packed inputs must be contiguous uint8"); TORCH_CHECK(x.size(0) >= 1 && x.size(0) <= 8 && x.size(1) > 0 && x.size(1) <= 8192, "supported rows 1..8 and packed K 1..8192"); TORCH_CHECK(wn.scalar_type() == torch::kBFloat16 && xn.scalar_type() == torch::kFloat, "norm dtypes must be BF16 weights and FP32 activations"); TORCH_CHECK(ac.scalar_type() == torch::kChar && wc.scalar_type() == torch::kChar && ac.numel() == 16 && wc.numel() == 16, "codebooks must contain 16 INT8 entries"); TORCH_CHECK(out.dim() == 2 && out.size(0) == x.size(0) && out.size(1) == wn.numel() && xn.numel() == x.size(0), "output and norm shapes mismatch"); TORCH_CHECK(w.numel() == wn.numel() * x.size(1), "packed weight size mismatch"); TORCH_CHECK(out.scalar_type() == torch::kBFloat16 || out.scalar_type() == torch::kHalf, "output must be BF16 or FP16"); if (has_bias) TORCH_CHECK(bias.device() == x.device() && bias.is_contiguous() && bias.scalar_type() == out.scalar_type() && bias.numel() == wn.numel(), "invalid bias"); if (wn.numel() == 0) return; const at::cuda::OptionalCUDAGuard guard(device_of(x)); const dim3 grid((wn.numel() + 3) / 4, x.size(0)); const auto stream = at::cuda::getCurrentCUDAStream(); #define LAUNCH(T) packed_gemv<<>>(out.data_ptr(), x.data_ptr(), w.data_ptr(), xn.data_ptr(), wn.data_ptr(), ac.data_ptr(), wc.data_ptr(), has_bias ? bias.data_ptr() : nullptr, wn.numel(), x.size(1), activation_scale, weight_scale) if (out.scalar_type() == torch::kBFloat16) { LAUNCH(c10::BFloat16); } else { LAUNCH(c10::Half); } #undef LAUNCH C10_CUDA_KERNEL_LAUNCH_CHECK(); }