makepad/libs/ai/cuda/kernels/nvfp4.cu
Admin 7f59912916 libs/ai: one AI stack, replacing libs/ggml, llama, mlx, cuda, tts, voice2 and pbr_paint
The model code was spread across eight crates that had grown into each other:
ggml and cuda and mlx each owned part of a tensor runtime, llama and tts and
voice2 each owned part of a model, and libs/diffusion owned everything else.
They are now one tree with an explicit shape:

  libs/ai/cuda     — kernels and launch surface
  libs/ai/metal    — Metal shaders and the shim
  libs/ai/llm      — the language-model runtime (sessions, lanes, contexts,
                     the CUDA and Metal executors, the compiled Metal path)
  libs/ai/models/  — common, flux, h3, music, paint, speech, stems, vision

libs/diffusion is not deleted but demoted: what remains is the VALIDATOR
crate — several dozen `*_validate.rs` oracles that check a native
implementation against a reference, which is where they belong now that the
implementations live next door.

The functional work inside the move is mostly in the LLM runtime: N lanes that
draft while one verify batch serves all of them, per-slot prefill over a shared
folded attention arena, speculation that survives batching, and a scheduler
that reports rather than publishes. And in the CUDA build: a machine without
usable CUDA must still LINK (and say so), the default kernel arch is the
building machine's GPU, `NO_CUDA` forces the stub even where the toolkit
exists, and kernels compile in parallel with progress.

libs/video_flow is new here: classical optical flow estimation and the `mkfl`
motion-field payload — a flow field measured from a clip without a model,
which is what drives free-rate bounce-looping playback and the uprez/tween
enhance pipe.
2026-08-23 01:34:35 +02:00

768 lines
26 KiB
Text

#include <cuda_fp16.h>
#include <cuda_runtime.h>
#if CUDART_VERSION >= 11080
#include <cuda_fp8.h>
#define MAKEPAD_GGML_CUDA_FP8_AVAILABLE
#endif
#include <stdint.h>
static constexpr uint32_t QK8_1 = 32;
static constexpr uint32_t QK_NVFP4 = 64;
static constexpr uint32_t QK_NVFP4_SUB = 16;
static constexpr uint32_t QI8_1 = 8;
typedef struct {
uint16_t d;
uint16_t s;
int8_t qs[QK8_1];
} __align__(4) block_q8_1;
typedef struct {
uint8_t d[QK_NVFP4 / QK_NVFP4_SUB];
uint8_t qs[QK_NVFP4 / 2];
} __align__(4) block_nvfp4;
static_assert(sizeof(block_q8_1) == 36, "wrong q8_1 block size");
static_assert(sizeof(block_nvfp4) == 36, "wrong nvfp4 block size");
__device__ __forceinline__ float makepad_cuda_f16_to_f32(uint16_t word) {
__half_raw raw;
raw.x = word;
return __half2float(*reinterpret_cast<__half *>(&raw));
}
static __device__ __forceinline__ float makepad_cuda_ue4m3_to_fp32(uint8_t x) {
#if defined(MAKEPAD_GGML_CUDA_FP8_AVAILABLE)
const uint32_t bits = x * (x != 0x7F && x != 0xFF);
const __nv_fp8_e4m3 xf = *reinterpret_cast<const __nv_fp8_e4m3 *>(&bits);
return static_cast<float>(xf) * 0.5f;
#else
if (x == 0 || x == 0x7F || x == 0xFF) {
return 0.0f;
}
const int exp = (x >> 3) & 0xF;
const int man = x & 0x7;
const float raw = exp == 0 ? ldexpf((float) man, -9) : ldexpf(1.0f + (float) man / 8.0f, exp - 7);
return raw * 0.5f;
#endif
}
__device__ __constant__ int8_t KVALUES_MXFP4_X2[16] = {
0, 1, 2, 3, 4, 6, 8, 12, 0, -1, -2, -3, -4, -6, -8, -12,
};
static __device__ __forceinline__ int makepad_cuda_get_int_b4(const void * x, const int i32) {
return reinterpret_cast<const int *>(x)[i32];
}
static __device__ __forceinline__ int2 makepad_cuda_get_int_from_table_16(
const int q4,
const int8_t * table) {
const uint32_t * table32 = reinterpret_cast<const uint32_t *>(table);
uint32_t tmp[2];
const uint32_t low_high_selection_indices = 0x32103210u | ((static_cast<uint32_t>(q4) & 0x88888888u) >> 1);
#pragma unroll
for (uint32_t i = 0; i < 2; ++i) {
const uint32_t shift = 16u * i;
const uint32_t low = __byte_perm(table32[0], table32[1], static_cast<uint32_t>(q4) >> shift);
const uint32_t high = __byte_perm(table32[2], table32[3], static_cast<uint32_t>(q4) >> shift);
tmp[i] = __byte_perm(low, high, low_high_selection_indices >> shift);
}
return make_int2(
__byte_perm(tmp[0], tmp[1], 0x6420),
__byte_perm(tmp[0], tmp[1], 0x7531));
}
static __device__ __forceinline__ int makepad_cuda_dp4a(const int a, const int b, int c) {
#if __CUDA_ARCH__ >= 610
return __dp4a(a, b, c);
#else
const int8_t * a8 = reinterpret_cast<const int8_t *>(&a);
const int8_t * b8 = reinterpret_cast<const int8_t *>(&b);
return c + a8[0] * b8[0] + a8[1] * b8[1] + a8[2] * b8[2] + a8[3] * b8[3];
#endif
}
template <int WIDTH>
static __device__ __forceinline__ float makepad_cuda_warp_reduce_sum(float x) {
#pragma unroll
for (int offset = WIDTH / 2; offset > 0; offset >>= 1) {
x += __shfl_xor_sync(0xffffffffu, x, offset, WIDTH);
}
return x;
}
template <int WIDTH>
static __device__ __forceinline__ float makepad_cuda_warp_reduce_max(float x) {
#pragma unroll
for (int offset = WIDTH / 2; offset > 0; offset >>= 1) {
x = fmaxf(x, __shfl_xor_sync(0xffffffffu, x, offset, WIDTH));
}
return x;
}
static __device__ __forceinline__ float makepad_cuda_e4m3fn_to_fp32(uint8_t x) {
#if defined(MAKEPAD_GGML_CUDA_FP8_AVAILABLE)
const uint32_t bits = x * (x != 0x7F && x != 0xFF);
const __nv_fp8_e4m3 xf = *reinterpret_cast<const __nv_fp8_e4m3 *>(&bits);
return static_cast<float>(xf);
#else
if (x == 0 || x == 0x7F || x == 0xFF) {
return 0.0f;
}
const int exp = (x >> 3) & 0xF;
const int man = x & 0x7;
if (exp == 0) {
return ldexpf(static_cast<float>(man), -9);
}
return ldexpf(1.0f + static_cast<float>(man) / 8.0f, exp - 7);
#endif
}
static __device__ __forceinline__ uint8_t makepad_cuda_fp32_to_e4m3fn(float x) {
#if CUDART_VERSION >= 12080
return __nv_cvt_float_to_fp8(x, __NV_SATFINITE, __NV_E4M3);
#else
if (!(x > 0.0f)) {
return 0;
}
uint8_t best = 0;
float best_err = x;
for (uint32_t i = 1; i < 0x7F; ++i) {
const uint8_t e4m3 = static_cast<uint8_t>(i);
const float v = makepad_cuda_e4m3fn_to_fp32(e4m3);
const float err = fabsf(v - x);
if (err < best_err) {
best = e4m3;
best_err = err;
}
}
return best;
#endif
}
static __device__ __forceinline__ uint8_t makepad_cuda_float_to_fp4_e2m1(float x, float e) {
const uint8_t sign_bit = static_cast<uint8_t>((x < 0.0f) << 3);
const float ax = fabsf(x) * e;
static constexpr float POS_LUT[8] = { 0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 3.0f, 4.0f, 6.0f };
int best_i = 0;
float best_err = fabsf(ax - POS_LUT[0]);
#pragma unroll
for (int i = 1; i < 8; ++i) {
const float err = fabsf(ax - POS_LUT[i]);
if (err < best_err) {
best_err = err;
best_i = i;
}
}
return static_cast<uint8_t>(best_i | sign_bit);
}
static __device__ __forceinline__ float makepad_cuda_vec_dot_nvfp4_q8_1(
const void * __restrict__ vbq,
const block_q8_1 * __restrict__ bq8_1,
const int32_t kbx,
const int32_t iqs) {
const block_nvfp4 * bq4 = reinterpret_cast<const block_nvfp4 *>(vbq) + kbx;
float sum = 0.0f;
#pragma unroll
for (int i = 0; i < 2; ++i) {
const int32_t iqs0 = iqs + 2 * i;
const int32_t iqs1 = iqs0 + 1;
const int32_t is = iqs0 >> 1;
const int2 v0 = makepad_cuda_get_int_from_table_16(
makepad_cuda_get_int_b4(bq4->qs, iqs0),
KVALUES_MXFP4_X2);
const int2 v1 = makepad_cuda_get_int_from_table_16(
makepad_cuda_get_int_b4(bq4->qs, iqs1),
KVALUES_MXFP4_X2);
const block_q8_1 * bq8 = bq8_1 + (is >> 1);
const int32_t i8 = ((is & 1) << 2);
int sumi = makepad_cuda_dp4a(v0.x, makepad_cuda_get_int_b4(bq8->qs, i8 + 0), 0);
sumi = makepad_cuda_dp4a(v0.y, makepad_cuda_get_int_b4(bq8->qs, i8 + 2), sumi);
sumi = makepad_cuda_dp4a(v1.x, makepad_cuda_get_int_b4(bq8->qs, i8 + 1), sumi);
sumi = makepad_cuda_dp4a(v1.y, makepad_cuda_get_int_b4(bq8->qs, i8 + 3), sumi);
const float d = makepad_cuda_ue4m3_to_fp32(bq4->d[is]) * makepad_cuda_f16_to_f32(bq8->d);
sum += d * static_cast<float>(sumi);
}
return sum;
}
static __device__ __forceinline__ float makepad_cuda_vec_dot_nvfp4_nvfp4_modelopt(
const void * __restrict__ vx,
const block_nvfp4 * __restrict__ vy,
const int32_t kbx,
const int32_t iqs) {
const block_nvfp4 * bx = reinterpret_cast<const block_nvfp4 *>(vx) + kbx;
float sum = 0.0f;
#pragma unroll
for (int i = 0; i < 2; ++i) {
const int32_t iqs0 = iqs + 2 * i;
const int32_t iqs1 = iqs0 + 1;
const int32_t is = iqs0 >> 1;
const int2 x0 = makepad_cuda_get_int_from_table_16(
makepad_cuda_get_int_b4(bx->qs, iqs0),
KVALUES_MXFP4_X2);
const int2 x1 = makepad_cuda_get_int_from_table_16(
makepad_cuda_get_int_b4(bx->qs, iqs1),
KVALUES_MXFP4_X2);
const int2 y0 = makepad_cuda_get_int_from_table_16(
makepad_cuda_get_int_b4(vy->qs, iqs0),
KVALUES_MXFP4_X2);
const int2 y1 = makepad_cuda_get_int_from_table_16(
makepad_cuda_get_int_b4(vy->qs, iqs1),
KVALUES_MXFP4_X2);
int sumi = makepad_cuda_dp4a(x0.x, y0.x, 0);
sumi = makepad_cuda_dp4a(x0.y, y0.y, sumi);
sumi = makepad_cuda_dp4a(x1.x, y1.x, sumi);
sumi = makepad_cuda_dp4a(x1.y, y1.y, sumi);
const float d = makepad_cuda_ue4m3_to_fp32(bx->d[is]) *
(0.5f * makepad_cuda_e4m3fn_to_fp32(vy->d[is]));
sum += d * static_cast<float>(sumi);
}
return sum;
}
static __launch_bounds__(128, 1) __global__ void makepad_cuda_nvfp4_q8_1_matvec_kernel(
const block_q8_1 * __restrict__ input_q8_1,
const block_nvfp4 * __restrict__ packed_weights_nvfp4,
float * __restrict__ output_f32,
uint32_t blocks_per_row,
uint32_t out_rows) {
constexpr int warp_size = 32;
constexpr int nwarps = 4;
constexpr int qi = QK_NVFP4 / (4 * 2);
constexpr int vdr = 4;
constexpr int blocks_per_iter = vdr * nwarps * warp_size / qi;
const uint32_t row = blockIdx.x;
if (row >= out_rows) {
return;
}
const int lane = threadIdx.x;
const int warp = threadIdx.y;
const int tid = warp_size * warp + lane;
const int blocks_per_q8 = QK_NVFP4 / QK8_1;
const int kbx_offset = static_cast<int>(row * blocks_per_row);
float tmp = 0.0f;
for (int kbx = tid / 2; kbx < static_cast<int>(blocks_per_row); kbx += blocks_per_iter) {
const int kby = kbx * blocks_per_q8;
const int kqs = vdr * (tid % 2);
tmp += makepad_cuda_vec_dot_nvfp4_q8_1(
packed_weights_nvfp4,
input_q8_1 + kby,
kbx_offset + kbx,
kqs);
}
__shared__ float tmp_shared[nwarps - 1][warp_size];
if (warp > 0) {
tmp_shared[warp - 1][lane] = tmp;
}
__syncthreads();
if (warp > 0) {
return;
}
#pragma unroll
for (int w = 0; w < nwarps - 1; ++w) {
tmp += tmp_shared[w][lane];
}
tmp = makepad_cuda_warp_reduce_sum<warp_size>(tmp);
if (lane == 0) {
output_f32[row] = tmp;
}
}
static __launch_bounds__(128, 1) __global__ void makepad_cuda_nvfp4_q8_1_matmul_kernel(
const block_q8_1 * __restrict__ input_q8_1,
const block_nvfp4 * __restrict__ packed_weights_nvfp4,
float * __restrict__ output_f32,
uint32_t blocks_per_row,
uint32_t out_rows,
uint32_t input_rows) {
constexpr int warp_size = 32;
constexpr int nwarps = 4;
constexpr int qi = QK_NVFP4 / (4 * 2);
constexpr int vdr = 4;
constexpr int blocks_per_iter = vdr * nwarps * warp_size / qi;
const uint32_t row = blockIdx.x;
const uint32_t input_row = blockIdx.y;
if (row >= out_rows || input_row >= input_rows) {
return;
}
const int lane = threadIdx.x;
const int warp = threadIdx.y;
const int tid = warp_size * warp + lane;
const int blocks_per_q8 = QK_NVFP4 / QK8_1;
const int q8_blocks_per_input_row = static_cast<int>(blocks_per_row * blocks_per_q8);
const int kbx_offset = static_cast<int>(row * blocks_per_row);
const block_q8_1 * input_row_q8_1 =
input_q8_1 + static_cast<int>(input_row) * q8_blocks_per_input_row;
float tmp = 0.0f;
for (int kbx = tid / 2; kbx < static_cast<int>(blocks_per_row); kbx += blocks_per_iter) {
const int kby = kbx * blocks_per_q8;
const int kqs = vdr * (tid % 2);
tmp += makepad_cuda_vec_dot_nvfp4_q8_1(
packed_weights_nvfp4,
input_row_q8_1 + kby,
kbx_offset + kbx,
kqs);
}
__shared__ float tmp_shared[nwarps - 1][warp_size];
if (warp > 0) {
tmp_shared[warp - 1][lane] = tmp;
}
__syncthreads();
if (warp > 0) {
return;
}
#pragma unroll
for (int w = 0; w < nwarps - 1; ++w) {
tmp += tmp_shared[w][lane];
}
tmp = makepad_cuda_warp_reduce_sum<warp_size>(tmp);
if (lane == 0) {
output_f32[input_row * out_rows + row] = tmp;
}
}
template <int rows_per_block>
static __launch_bounds__(128, 1) __global__ void makepad_cuda_nvfp4_nvfp4_matvec_kernel(
const block_nvfp4 * __restrict__ input_nvfp4,
const block_nvfp4 * __restrict__ packed_weights_nvfp4,
float input_scale,
float * __restrict__ output_f32,
uint32_t blocks_per_row,
uint32_t out_rows) {
constexpr int warp_size = 32;
constexpr int nwarps = 4;
constexpr int qi = QK_NVFP4 / (4 * 2);
constexpr int vdr = 4;
constexpr int blocks_per_iter = vdr * nwarps * warp_size / qi;
const uint32_t row0 = blockIdx.x * rows_per_block;
if (row0 >= out_rows) {
return;
}
const int lane = threadIdx.x;
const int warp = threadIdx.y;
const int tid = warp_size * warp + lane;
float tmp[rows_per_block] = {0.0f};
for (int kbx = tid / 2; kbx < static_cast<int>(blocks_per_row); kbx += blocks_per_iter) {
const int kqs = vdr * (tid % 2);
const block_nvfp4 * input_block = input_nvfp4 + kbx;
#pragma unroll
for (int row_idx = 0; row_idx < rows_per_block; ++row_idx) {
const uint32_t row = row0 + row_idx;
if (row < out_rows) {
tmp[row_idx] += makepad_cuda_vec_dot_nvfp4_nvfp4_modelopt(
packed_weights_nvfp4,
input_block,
static_cast<int>(row * blocks_per_row) + kbx,
kqs);
}
}
}
__shared__ float tmp_shared[nwarps - 1][rows_per_block][warp_size];
if (warp > 0) {
#pragma unroll
for (int row_idx = 0; row_idx < rows_per_block; ++row_idx) {
tmp_shared[warp - 1][row_idx][lane] = tmp[row_idx];
}
}
__syncthreads();
if (warp > 0) {
return;
}
#pragma unroll
for (int row_idx = 0; row_idx < rows_per_block; ++row_idx) {
float row_sum = tmp[row_idx];
#pragma unroll
for (int w = 0; w < nwarps - 1; ++w) {
row_sum += tmp_shared[w][row_idx][lane];
}
row_sum = makepad_cuda_warp_reduce_sum<warp_size>(row_sum) * input_scale;
if (lane == 0) {
const uint32_t row = row0 + row_idx;
if (row < out_rows) {
output_f32[row] = row_sum;
}
}
}
}
static __launch_bounds__(128, 1) __global__ void makepad_cuda_nvfp4_nvfp4_matmul_kernel(
const block_nvfp4 * __restrict__ input_nvfp4,
const block_nvfp4 * __restrict__ packed_weights_nvfp4,
float input_scale,
float * __restrict__ output_f32,
uint32_t blocks_per_row,
uint32_t out_rows,
uint32_t input_rows) {
constexpr int warp_size = 32;
constexpr int nwarps = 4;
constexpr int qi = QK_NVFP4 / (4 * 2);
constexpr int vdr = 4;
constexpr int blocks_per_iter = vdr * nwarps * warp_size / qi;
const uint32_t row = blockIdx.x;
const uint32_t input_row = blockIdx.y;
if (row >= out_rows || input_row >= input_rows) {
return;
}
const int lane = threadIdx.x;
const int warp = threadIdx.y;
const int tid = warp_size * warp + lane;
const int kbx_offset = static_cast<int>(row * blocks_per_row);
const block_nvfp4 * input_row_nvfp4 =
input_nvfp4 + static_cast<int>(input_row) * static_cast<int>(blocks_per_row);
float tmp = 0.0f;
for (int kbx = tid / 2; kbx < static_cast<int>(blocks_per_row); kbx += blocks_per_iter) {
const int kqs = vdr * (tid % 2);
tmp += makepad_cuda_vec_dot_nvfp4_nvfp4_modelopt(
packed_weights_nvfp4,
input_row_nvfp4 + kbx,
kbx_offset + kbx,
kqs);
}
__shared__ float tmp_shared[nwarps - 1][warp_size];
if (warp > 0) {
tmp_shared[warp - 1][lane] = tmp;
}
__syncthreads();
if (warp > 0) {
return;
}
#pragma unroll
for (int w = 0; w < nwarps - 1; ++w) {
tmp += tmp_shared[w][lane];
}
tmp = makepad_cuda_warp_reduce_sum<warp_size>(tmp) * input_scale;
if (lane == 0) {
output_f32[input_row * out_rows + row] = tmp;
}
}
static __launch_bounds__(QK_NVFP4, 1) __global__ void makepad_cuda_quantize_nvfp4_f32_kernel(
const float * __restrict__ input_f32,
float input_scale,
block_nvfp4 * __restrict__ output_nvfp4) {
const uint32_t block_idx = blockIdx.x;
const uint32_t lane = threadIdx.x;
const uint32_t base = block_idx * QK_NVFP4;
const uint32_t sub = lane / QK_NVFP4_SUB;
const uint32_t lane_sub = lane % QK_NVFP4_SUB;
__shared__ uint8_t q_shared[QK_NVFP4];
__shared__ float d_shared[QK_NVFP4 / QK_NVFP4_SUB];
const float in_s = input_scale != 0.0f ? input_scale : 1.0f;
const float in_s_inv = 1.0f / in_s;
const float xi = input_f32[base + lane];
float amax = fabsf(xi);
amax = makepad_cuda_warp_reduce_max<QK_NVFP4_SUB>(amax);
if (lane_sub == 0) {
const uint8_t e4m3 = makepad_cuda_fp32_to_e4m3fn((amax / 6.0f) * in_s_inv);
output_nvfp4[block_idx].d[sub] = e4m3;
d_shared[sub] = makepad_cuda_e4m3fn_to_fp32(e4m3);
}
__syncthreads();
const float d = d_shared[sub] * in_s;
const float d_inv = d != 0.0f ? 1.0f / d : 0.0f;
q_shared[lane] = makepad_cuda_float_to_fp4_e2m1(xi, d_inv) & 0x0F;
__syncthreads();
if (lane_sub < QK_NVFP4_SUB / 2) {
output_nvfp4[block_idx].qs[sub * (QK_NVFP4_SUB / 2) + lane_sub] =
q_shared[sub * QK_NVFP4_SUB + lane_sub] |
(q_shared[sub * QK_NVFP4_SUB + lane_sub + QK_NVFP4_SUB / 2] << 4);
}
}
static __global__ void makepad_cuda_nvfp4_get_row_f32_kernel(
const block_nvfp4 * __restrict__ packed_weights_nvfp4,
float * __restrict__ output_f32) {
const uint32_t block_idx = blockIdx.x;
const uint32_t tid = threadIdx.x;
const block_nvfp4 & xb = packed_weights_nvfp4[block_idx];
const uint32_t sub = tid / (QK_NVFP4_SUB / 2);
const uint32_t j = tid % (QK_NVFP4_SUB / 2);
const float d = makepad_cuda_ue4m3_to_fp32(xb.d[sub]);
const uint8_t packed = xb.qs[sub * (QK_NVFP4_SUB / 2) + j];
const uint32_t base = block_idx * QK_NVFP4 + sub * QK_NVFP4_SUB;
output_f32[base + j] = d * (float) KVALUES_MXFP4_X2[packed & 0x0F];
output_f32[base + QK_NVFP4_SUB / 2 + j] = d * (float) KVALUES_MXFP4_X2[packed >> 4];
}
static __global__ void makepad_cuda_nvfp4_get_row_f32_device_u32_kernel(
const block_nvfp4 * __restrict__ packed_weights_nvfp4,
const uint32_t * __restrict__ row_index_device_u32,
uint32_t blocks_per_row,
float * __restrict__ output_f32) {
const uint32_t row_index = *row_index_device_u32;
const uint32_t block_idx = blockIdx.x;
const uint32_t tid = threadIdx.x;
const block_nvfp4 & xb = packed_weights_nvfp4[row_index * blocks_per_row + block_idx];
const uint32_t sub = tid / (QK_NVFP4_SUB / 2);
const uint32_t j = tid % (QK_NVFP4_SUB / 2);
const float d = makepad_cuda_ue4m3_to_fp32(xb.d[sub]);
const uint8_t packed = xb.qs[sub * (QK_NVFP4_SUB / 2) + j];
const uint32_t base = block_idx * QK_NVFP4 + sub * QK_NVFP4_SUB;
output_f32[base + j] = d * (float) KVALUES_MXFP4_X2[packed & 0x0F];
output_f32[base + QK_NVFP4_SUB / 2 + j] = d * (float) KVALUES_MXFP4_X2[packed >> 4];
}
static __global__ void makepad_cuda_nvfp4_get_rows_f32_device_u32_kernel(
const block_nvfp4 * __restrict__ packed_weights_nvfp4,
const uint32_t * __restrict__ row_indices_device_u32,
uint32_t blocks_per_row,
float * __restrict__ output_f32,
uint32_t output_row_stride) {
const uint32_t block_idx = blockIdx.x;
const uint32_t row_slot = blockIdx.y;
const uint32_t tid = threadIdx.x;
const uint32_t row_index = row_indices_device_u32[row_slot];
const block_nvfp4 & xb = packed_weights_nvfp4[row_index * blocks_per_row + block_idx];
const uint32_t sub = tid / (QK_NVFP4_SUB / 2);
const uint32_t j = tid % (QK_NVFP4_SUB / 2);
const float d = makepad_cuda_ue4m3_to_fp32(xb.d[sub]);
const uint8_t packed = xb.qs[sub * (QK_NVFP4_SUB / 2) + j];
const uint32_t base = row_slot * output_row_stride + block_idx * QK_NVFP4 + sub * QK_NVFP4_SUB;
output_f32[base + j] = d * (float) KVALUES_MXFP4_X2[packed & 0x0F];
output_f32[base + QK_NVFP4_SUB / 2 + j] = d * (float) KVALUES_MXFP4_X2[packed >> 4];
}
extern "C" cudaError_t makepad_cuda_nvfp4_q8_1_matvec(
const uint8_t * input_q8_1_bytes,
const uint8_t * packed_weights_nvfp4_bytes,
float * output_f32,
uint32_t q8_1_blocks,
uint32_t out_rows,
cudaStream_t stream) {
if (q8_1_blocks == 0 || (q8_1_blocks % 2) != 0) {
return cudaErrorInvalidValue;
}
const uint32_t blocks_per_row = q8_1_blocks / 2;
const dim3 grid(out_rows, 1, 1);
const dim3 block(32, 4, 1);
makepad_cuda_nvfp4_q8_1_matvec_kernel<<<grid, block, 0, stream>>>(
reinterpret_cast<const block_q8_1 *>(input_q8_1_bytes),
reinterpret_cast<const block_nvfp4 *>(packed_weights_nvfp4_bytes),
output_f32,
blocks_per_row,
out_rows
);
return cudaGetLastError();
}
extern "C" cudaError_t makepad_cuda_nvfp4_q8_1_matmul(
const uint8_t * input_q8_1_bytes,
const uint8_t * packed_weights_nvfp4_bytes,
float * output_f32,
uint32_t q8_1_blocks,
uint32_t out_rows,
uint32_t input_rows,
cudaStream_t stream) {
if (q8_1_blocks == 0 || (q8_1_blocks % 2) != 0 || input_rows == 0) {
return cudaErrorInvalidValue;
}
const uint32_t blocks_per_row = q8_1_blocks / 2;
const dim3 grid(out_rows, input_rows, 1);
const dim3 block(32, 4, 1);
makepad_cuda_nvfp4_q8_1_matmul_kernel<<<grid, block, 0, stream>>>(
reinterpret_cast<const block_q8_1 *>(input_q8_1_bytes),
reinterpret_cast<const block_nvfp4 *>(packed_weights_nvfp4_bytes),
output_f32,
blocks_per_row,
out_rows,
input_rows
);
return cudaGetLastError();
}
extern "C" cudaError_t makepad_cuda_quantize_nvfp4_f32(
const float * input_f32,
float input_scale,
uint8_t * output_nvfp4_bytes,
uint32_t n,
cudaStream_t stream) {
if (n == 0 || (n % QK_NVFP4) != 0) {
return cudaErrorInvalidValue;
}
makepad_cuda_quantize_nvfp4_f32_kernel<<<n / QK_NVFP4, QK_NVFP4, 0, stream>>>(
input_f32,
input_scale,
reinterpret_cast<block_nvfp4 *>(output_nvfp4_bytes)
);
return cudaGetLastError();
}
extern "C" cudaError_t makepad_cuda_nvfp4_nvfp4_matvec(
const uint8_t * input_nvfp4_bytes,
const uint8_t * packed_weights_nvfp4_bytes,
float input_scale,
float * output_f32,
uint32_t nvfp4_blocks,
uint32_t out_rows,
cudaStream_t stream) {
if (nvfp4_blocks == 0) {
return cudaErrorInvalidValue;
}
const dim3 block(32, 4, 1);
if (out_rows >= 32768) {
constexpr uint32_t rows_per_block = 4;
const dim3 grid((out_rows + rows_per_block - 1) / rows_per_block, 1, 1);
makepad_cuda_nvfp4_nvfp4_matvec_kernel<rows_per_block><<<grid, block, 0, stream>>>(
reinterpret_cast<const block_nvfp4 *>(input_nvfp4_bytes),
reinterpret_cast<const block_nvfp4 *>(packed_weights_nvfp4_bytes),
input_scale,
output_f32,
nvfp4_blocks,
out_rows
);
} else {
constexpr uint32_t rows_per_block = 1;
const dim3 grid((out_rows + rows_per_block - 1) / rows_per_block, 1, 1);
makepad_cuda_nvfp4_nvfp4_matvec_kernel<rows_per_block><<<grid, block, 0, stream>>>(
reinterpret_cast<const block_nvfp4 *>(input_nvfp4_bytes),
reinterpret_cast<const block_nvfp4 *>(packed_weights_nvfp4_bytes),
input_scale,
output_f32,
nvfp4_blocks,
out_rows
);
}
return cudaGetLastError();
}
extern "C" cudaError_t makepad_cuda_nvfp4_nvfp4_matmul(
const uint8_t * input_nvfp4_bytes,
const uint8_t * packed_weights_nvfp4_bytes,
float input_scale,
float * output_f32,
uint32_t nvfp4_blocks,
uint32_t out_rows,
uint32_t input_rows,
cudaStream_t stream) {
if (nvfp4_blocks == 0 || input_rows == 0) {
return cudaErrorInvalidValue;
}
const dim3 grid(out_rows, input_rows, 1);
const dim3 block(32, 4, 1);
makepad_cuda_nvfp4_nvfp4_matmul_kernel<<<grid, block, 0, stream>>>(
reinterpret_cast<const block_nvfp4 *>(input_nvfp4_bytes),
reinterpret_cast<const block_nvfp4 *>(packed_weights_nvfp4_bytes),
input_scale,
output_f32,
nvfp4_blocks,
out_rows,
input_rows
);
return cudaGetLastError();
}
extern "C" cudaError_t makepad_cuda_nvfp4_get_row_f32(
const uint8_t * packed_weights_nvfp4_bytes,
float * output_f32,
uint32_t n_cols,
uint32_t row_index,
cudaStream_t stream) {
if ((n_cols % QK_NVFP4) != 0) {
return cudaErrorInvalidValue;
}
const uint32_t blocks_per_row = n_cols / QK_NVFP4;
const block_nvfp4 * row_ptr =
reinterpret_cast<const block_nvfp4 *>(packed_weights_nvfp4_bytes) + row_index * blocks_per_row;
makepad_cuda_nvfp4_get_row_f32_kernel<<<blocks_per_row, 32, 0, stream>>>(
row_ptr,
output_f32
);
return cudaGetLastError();
}
extern "C" cudaError_t makepad_cuda_nvfp4_get_row_f32_device_u32(
const uint8_t * packed_weights_nvfp4_bytes,
float * output_f32,
uint32_t n_cols,
const uint32_t * row_index_device_u32,
cudaStream_t stream) {
if ((n_cols % QK_NVFP4) != 0) {
return cudaErrorInvalidValue;
}
const uint32_t blocks_per_row = n_cols / QK_NVFP4;
makepad_cuda_nvfp4_get_row_f32_device_u32_kernel<<<blocks_per_row, 32, 0, stream>>>(
reinterpret_cast<const block_nvfp4 *>(packed_weights_nvfp4_bytes),
row_index_device_u32,
blocks_per_row,
output_f32
);
return cudaGetLastError();
}
extern "C" cudaError_t makepad_cuda_nvfp4_get_rows_f32_device_u32(
const uint8_t * packed_weights_nvfp4_bytes,
const uint32_t * row_indices_device_u32,
float * output_f32,
uint32_t n_cols,
uint32_t row_count,
uint32_t output_row_stride,
cudaStream_t stream) {
if ((n_cols % QK_NVFP4) != 0 || row_count == 0 || output_row_stride < n_cols) {
return cudaErrorInvalidValue;
}
const uint32_t blocks_per_row = n_cols / QK_NVFP4;
const dim3 grid(blocks_per_row, row_count, 1);
makepad_cuda_nvfp4_get_rows_f32_device_u32_kernel<<<grid, 32, 0, stream>>>(
reinterpret_cast<const block_nvfp4 *>(packed_weights_nvfp4_bytes),
row_indices_device_u32,
blocks_per_row,
output_f32,
output_row_stride
);
return cudaGetLastError();
}